Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

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;
}

Функции для работы с объектом Событие

Часто бывает нужно, чтобы поток был готов к выполнению на протяжении всего времени работы процесса, но приводился в действие (выполнялся) только при необходимости. Если этот вторичный поток мог бы обрабатывать сообщения, то ему можно было посылать определенное в программе сообщение, а он бы выполнял свои действия только после его получения. Но

  • Чаще всего вторичные потоки не могут обрабатывать сообщения, так как не создают окон. Это идеальный случай для применения объекта Событие (event object).События - самая примитивная разновидность объектов ядра. Они содержат счетчик числа пользователей (как и все объекты ядра) и две булевы переменные: одна сообщает тип данного объекта-события, другая — его состояние (свободен или занят).

Объект событие может быть либо установленным (свободным), либо сброшенным (занятым). Объект событие можно создать с помощью функции:

HANDLE event=CreateEvent(NULL,fManual,fInitial,szName);

· Первый параметр (указатель на структуру типа SECURITY_ATTRIBUTES) и последний параметр (имя объекта событие ) имеют смысл только в том случае, когда объект событие разделяется между процессами. В случае с одним процессом эти параметры обычно имеют значение NULL.


· Если параметр fManual при вызове функции CreateEvent имеет значение FALSE, то объект событие автоматически будет становиться сброшенным, когда осуществляется возврат из функции WaitForSingleObject. Если fManual равно TRUE, то при необходимости приложение должно самостоятельно сбрасывать его при помощи функции ResetEvent.


· Следует установить значение параметра fInitial равным TRUE, если необходимо, чтобы объект событие был изначально установленным, или равным FALSE, чтобы он был сброшенным.

Для того чтобы сделать уже существующий объект событие установленным, используется функция:

SetEvent(event);

Чтобы сделать объект событие сброшенным, следует вызвать функцию:

ResetEvent(event);

Для проверки того, установлено ли событие, функция потока обычно вызывает функцию WaitForSingleObject со вторым параметром, равным INFINITY:

WaitForSingleObject(event, INFINITY);
  • Возврат из функции WaitForSingleObject происходит немедленно, если объект событие в настоящее время установлен. В противном случае поток будет приостановлен в функции до тех пор, пока объект событие не станет установленным.


  • Можно установить максимальное значение периода ожидания, задав его величину в миллисекундах. Тогда возврат из функции WaitForSingleObject произойдет, когда объект событие станет свободным или если истечет время ожидания.

Замечание. Напомним, что если параметр fManual при вызове функции CreateEvent имеет значение FALSE, то объект событие автоматически становится занятым, когда осуществляется возврат из функции WaitForSingleObject. Эта особенность позволяет избежать использования функции ResetEvent.

Уведомление при помощи объекта Событие

Приведем примерные действия по использованию объекта событие.

Определим структуру, которая будет использоваться для хранения общих переменных главного и вторичного потоков:

struct PARAM { BOOL type; // тип выполняемых потоком действий HWND wnd; // окно, в оконной процедуре которого создается поток BOOL stop; // признак завершения работы потока HANDLE event; // объект-событие, поток работает, если оно установлено};

Рассмотрим оконную процедуру, в которой создается поток, выполняющийся параллельно с главным потоком. Поток запускается на этапе создания окна главного потока, но находится в приостановленном состоянии до тех пор, пока пользователь его не выберет команду меню, приводящую поток в действие. Приостановкой потока и его возобновлением, а также типом выполняемого потоком действия, управляет пользователь при помощи команд меню.

#define IDM_CIRCLES 1#define IDM_BARS 2#define IDM_STOP 3#define IDM_BEGIN 4... LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ static struct PARAM p; // используется как общая память потоков... switch(msg) { case WM_CREATE: { // создание изначально сброшенного объекта событие – третий // аргумент равен FALSE, при этом объект событие не будет // автоматически становиться занятым при выходе из функции // WaitForSingleObject – второй аргумент равен TRUE // (первый и посл. аргументы - для объектов, разделяемых процессами) p.event=CreateEvent(NULL,TRUE,FALSE,NULL); // запись в общую память потоков, создание и запуск потока, // который выполняется, если объект событие установлено p.type=0; p.wnd=hWnd; p.stop=0; _beginthread(ThreadFun,0,(void *)(&p)); }; break; case WM_COMMAND: // обработка сообщений от меню { switch(LOWORD(wParam)) { case IDM_BEGIN: // выполнение потока { // сделать события установленным SetEvent(p.event); }; break; case IDM_STOP: // приостановка потока { // сделать события сброшеным ResetEvent(p.event); }; break; case IDM_CIRCLES: // изменить тип действия { // записать тип выполняемого потоком действия p.type=0; }; break; case IDM_BARS: // изменить тип действия { // записать тип выполняемого потоком действия p.type=1; }; break; } }; return 0; case WM_DESTROY: { // записать признак завершения потока p.stop=1; PostQuitMessage(0); }; return 0l; // обработка других сообщений ... default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0l;}

Функция создаваемого вторичного потока в данном случае может иметь следующее определение:

void ThreadFun(void *lpvoid) { // автоматические переменные потока... // получение адреса общей памяти потоков struct PARAM *p=(struct PARAM *)lpvoid; while(! p->stop) // пока признак завершения не установлен { // ожидание установки объекта события - если объект событие установлено, // поток будет работать, если сброшено, то поток будет ждать, // пока эта функция возвратит управление WaitForSingleObject(p->event,INFINITE); // выполнение действия, определяемого p->type, при этом может // использоваться дескриптор создавшего поток окна, он хранится в p->wnd... } _endthread(); // полная остановка потока }

Вторичный поток создается при инициализации окна главного потока и готов к выполнению на протяжении существования этого окна, т.е. пока приложение не завершит свою работу. Но выполняться он будет только в случае, если пользователь при помощи команды меню инициирует установку объекта событие. При установке объекта события в сброшенное состояние поток вновь приостанавливается

 




Поделиться с друзьями:


Дата добавления: 2014-01-11; Просмотров: 726; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.01 сек.