Уведомление при помощи посылки сообщений
- Очень часто в процессе работы потокам следует знать информацию о состоянии другого потока (работает он или уже завершил свою работу), а также выполнять что-то после уведомления о каком-либо событии со стороны другого потока.
Рассмотрим случай, когда какому-либо потоку необходимо проинформировать первичный поток (или другой поток, умеющий обрабатывать сообщения, т.е. имеющий оконную процедуру) о своем состоянии или о том, что этому потоку следует что-либо сделать.
Любой поток может функцией SendMessage (или PostMessage) послать в оконную процедуру потока, умеющего обрабатывать сообщения,сообщение, определенное в программе. Получив такое сообщение, оконная процедура потока-адресата может сделать какие-либо действия, или может просто быть информированной о состоянии потока-отправителя, пославшего это сообщение.
Например, модифицируем функцию вторичного потока предыдущего примера так, чтобы она посылала сообщение в первичный поток через каждые 1000 итераций работы своего цикла, а функцию главного окна приложения - чтобы она обрабатывала это сообщение:
. . .#define MESSAGE_FROM_OTHER_THREAD (WM_USER+1) . . . LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { ... switch(msg) { ...case MESSAGE_FROM_OTHER_THREAD: {// первичный поток может здесь обработать данное сообщение. . . };break; . . . } return 0l; } void ThreadFun(void *lpvoid) { long num=0; . . . while(!p->stop) { num++;if (num%1000==0) {// посылка сообщения первичному потокуSendMessage(p->wnd,MESSAGE_FROM_OTHER_THREAD,0,0L); } . . . } _endthread(); } Объекты ядраСледующие объекты ядра бывают в свободном или занятом состоянии:
- процессы
- потоки
- задания
- файлы
- консольный ввод
- уведомления об изменении файлов
- события
- ожидаемые таймеры
- семафоры
- мьютексы
Так, объекты ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра "процесс", и он на всегда остается в этом состоянии
Объект ядра «процесс» пребывает в занятом состоянии, пока выполняется сопоставленный с ним процесс, и переходит в свободное состояние, когда процесс завершается Внутри этого объекта поддерживается булева переменная, которая при создании объекта инициализируется как FALSE («занято"). По окончании работы процесса операционная система меняет значение этой переменной на TRUE, сообщая тем самым, что объект свободен.
Существуют специальные функции, которые позволяют потоку ждать перехода определенного объекта ядра в свободное состояние.Wait-функции
Wait-функции позволяют потоку в любой момент приостановиться и ждать освобож дения какого-либо объекта ядра. Из всего семейства этих функций чаще всего исполь зуется WaitForSingleObject:
DWORD WaitForSingleObject( HANDLE hObject, DWORD dwMilliseconds);
Первый параметр, hObject, идентифицирует объект ядра, поддерживающий состояния «свободен-занят» Второй параметр, dwMilliseconds, указывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта.
Следующий вызов сообщает системе, что поток будет ждать до тех пор, пока не завершится процесс, идентифицируемый описателем hProcess.
WaitForSingleObject(hProcess, INFINITE);
Константа INFINITE, подсказывает системе, что вызывающий поток готов ждать этого события хоть целую вечность. Именно эта константа обычно и передается функции WaitForSingleObject, но Вы можете указать любое значение в миллисекундах. Кстати, константа INFINITE опре делена как 0xFFFFFFFF (или -1). Разумеется, передача INFINlTE нс всегда безопасна Если объект так и не перейдет в свободное состояние, вызывающий поток никогда не проснется; одно утешение, тратить драгоценное процессорное время он при этом не будет
Вот пример, иллюстрирующий, как вызывать WaitForSingleObject co значением тай маута, отличным от INFINITE
DWORD dw = WaitForSlngleObject(hProcess, 5000);
switch (dw)
{
case WAIT_OBJECT_0:
// процесс завершается
break;
case WAIT_TIMEOUT:
// процесс не завершился в течение 5000 мс
break;
case WAIT_FAILED:
// неправильный вызов функции (неверный описатель?)
break;
}
Данный код сообщает системе, что вызывающий поток не должен получать про цессорное время, пока не завершится указанный процесс или не пройдет 5000 мс (в зависимости от того, что случится раньше). Поэтому функция вернет управление либо до истечения 5000 мс, если процесс завершится, либо примерно через 5000 мс, если процесс к тому времени не закончит свою работу Заметьте, что в параметре dwMilli seconds можно передать 0, и гогда WaitForSingleObject немедленно вернет управление
Возвращаемое значение функции WaitForSingleObject указывает, почему вызывающий поток снова стал планируемым Если функция возвращает WAITOBTECT_0, объект свободен, а если WAIT_TIMEOUT — заданное время ожидания (таймаут) истекло. При передаче неверного параметра (например, недопустимого описателя) WaitForSing leObject возвращает WAIT_ EAILED. Чтобы выяснить конкретную причину ошибки, вы зовите функцию GetLastErroY.
Функция WaitForMultipleObjects аналогична WaitForSingleObject c тем исключением, что позволяет ждать освобождения сразу нескольких объектов или какого-то одного из списка объектов:
DWORD WaitForMultipleObjects( DWOHD dwCount, CONST HANDLE* phObjects, BOOL fWaitAll, DWORD dwMilliseconds);
Параметр dwCount определяет количество интересующих объектов ядра Его значение должло быть в пределах от 1 до MAXIMUM_WAIT_OBJECTS (в заголовочных файлах Windows оно определено как 64). Параметр phObject — это указатель на массив описателей объектов ядра.
WaitForMultipleObjects приостанавливает поток и заставляет его ждать освобождения либо всех заданных объектов ядра, либо одного из них. Параметр fWaitAll - если он равен TRUE, функция не даст потоку возобновить свою работу, пока не освободятся все объекты.
Параметр dwMilliseconds идентичен одноименному параметру функции WaitFor SingleObject.
Возвращаемое значение функции WaitForMultipleObjects сообщает, почему возобновилосъ выполнение вызвавшего ее потока Значения WAIT_FAILED и WAIT_TIMEOUT никаких пояснений не требуют. Если Вы передали TRUE в параметре fWaitAll и всс объекты перешли в свободное состояние, функция возвращает значение WAIT_OBJECT_0. Если fWaitAll приравнен FALSE, она возвращает управление, как только освобождается любой из объектов. В этом случае возвращается значение от WAIT_OBJECT_0 до WAIT_OBJECT_0 + dwCount – 1 - это индекс в массиве описателей, на который указывает второй параметр функции WaitForMultipleObjects, какой объект перешел в незанятое состояние. Пример.
HANDLE h[3];
h[0] = hProcess1;
h[1] = hProcess2;
h[2] = hProcess3,
DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000);
switch (dw)
{
case WAIT_FAILED:
// неправильный вызов функции (неверный описатель?)
break;
case WAIT_TIMEOUT:
// ни один из объектов не освободился в течение 5000 мс
break;
case WAIT_OBJECTJ) + 0:
// завершился процесс, идентифицируемый h[0], т e описателем (hProcess1)
break;
case WATT_OBJECT_0 + 1:
// завершился процесс, идентифицируемый h[1], т e описателем (hProcess2)
break;
case WAIT_OBJECT_0 + 2:
// завершился процесс, идентифицируемый h[2], т. e описателем (hProcess3)
break;
}
Дата добавления: 2017-01-26; просмотров: 1333;