Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СП2_1 Синхронизация потоков.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
134.14 Кб
Скачать

1. Создание объекта "ожидаемый таймер" производится следующей функцией:

HANDLE CreateWaitableTimer( LPSECURITY_ATTRIBUTES lpWTimerAttrib, BOOL fManualReset, LPCTSTR lpName);

Параметры функции:

- lpWTimerAttrib является указателем на структуру типа SECURITY_ATTRIBUTES, если не используется, то задается NULL;

- fManualReset указывает, какого типа таймер будет создан: со сбросом вручную (TRUE) или с автосбросом (FALSE);

- lpName указывает на строку, содержащую имя таймера, которое необходимо для доступа к объекту других процессов. Если не нужен именованный объект, то указывается NULL.

Функция CreateWaitableTimer возвращает описатель таймера, используемый для работы с ним.

Объекты «ожидаемый таймер» всегда создаются в занятом состоянии.

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

BOOL SetWaitableTimer( HANDLE hWTimer,

const LARGE_INTEGER *pDueTime, LONG lPeriod,

PTIMERAPCROUTINE pfnCompletionRoutine,

PVOID pvArgToCompletionRoutine, BOOL fResume);

где

- hWTimer – дескриптор ожидаемого таймера, возвращенный функцией CreateWaitableTimer;

- pDueTime указывает на целое 64-битное значение, где хранится дата и время (в формате UTC - Coordinated Universal Time) первого перехода таймера в свободное состояние. Если это значение имеет отрицательный знак, то его абсолютная величина указывает, через какой промежуток (в интервалах по 100 нс) после вызова данной функции таймер станет свободным;

- lPeriod задает периодичность (в миллисекундах) следующих переходов таймера в свободное состояние;

- pfnCompletionRoutine и pvArgToCompletionRoutine задают имя APC-функции, вызываемой при переходе таймера в свободное состояние и адрес передаваемых ей данных. APC – это асинхронный вызов функций (Asynchronous Procedure Call). Если такая функция не используется, то в обеих параметрах указываются NULL;

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

Функция возвращает TRUE, если ее вызов выполнен успешно и FALSE в противном случае.

3. Отключение срабатываний таймера производится функцией:

BOOL CancelWaitableTimer(HANDLE hWTimer);

После этого восстановить работу таймера можно повторным вызовом функции SetWaitableTimer() с заданием новых времени и периодичности.

4. Уничтожение объекта hWTimer и освобождение его дескриптора производится функцией:

BOOL CloseHandle(HANDLE hWTimer);

Взаимодействие потоков с ожидаемыми таймерами происходит следующим образом.

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

1) если таймер с автосбросом, то он автоматически сбрасывается в занятое состояние, при этом только один поток будет работать, а остальные потоки останутся ждать. Для возобновления работы потоков, ожидающих данного таймера необходимо вызвать функцию SetWaitableTimer(), задав новое время его срабатывания;

2) если таймер со сбросом вручную, то все потоки, ожидающие этот таймер, получат управление, а он так и останется в свободном состоянии, пока какой-нибудь поток не вызовет CancelWaitableTimer(). После этого возобновить работу таймера можно вызовом функции SetWaitableTimer() с заданием новых времени и периодичности.

Ожидаемые таймеры отличаются от обычных таймеров Windows (работающих в пользовательском режиме и настраиваемых функцией SetTimer()) следующим: во-первых они являются объектами ядра, а значит более защищенными; во-вторых они более точные, т.к. сообщения WM_TIMER, посылаемые обычными таймерами имеют низкий приоритет и в очереди сообщений обрабатываются последними.

Примечание: рассмотренные выше функции Win32 API для работы с ожидаемыми таймерами появились позже других функций для синхронизации потоков, начиная с версий Windows NT 4.0 и Windows 98. Поэтому описания прототипов этой группы функций в заголовочном файле WINBASE.H заключены в блок условной компиляции:

#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)

… // Прототипы функций для работы с ожид. таймерами

#endif

Тем самым ограничивается возможность использования этих функций в ранних версиях ОС Windows.

При работе с ожидаемыми таймерами в программе необходимо перед включением заголовочного файла StdAfx.h определить один из указанных в WINBASE.H идентификаторов:

#define _WIN32_WINNT 0x0400

#include <stdafx.h>

Примеры использования ожидаемых таймеров. (См. электронный вар-т)

Пример 1. Два потока синхронизируются объектом "ожидаемый таймер" с автосбросом. Время срабатывания таймера является относительным и задается в количестве интервалов по 100 нс. Первое срабатывание – через 10 мс после создания таймера, последующие – через 2 мс после завершения потоком своих операций. (1 мс равна 10000 интервалов по 100 нс).

#define _WIN32_WINNT 0x0400

HANDLE hWTimer;

LARGE_INTEGER li;

hWTimer=CreateWaitableTimer(NULL, FALSE, NULL);

// Задаем отрицательное число в количестве

// интервалов по 100 нс

li.QuadPart = - (10 * 10000);

// Устанавливаем первое срабатывание через 10 мс

SetWaitableTimer(hWTimer,&li, 0, NULL, NULL, FALSE);

// Функция потока 1

DWORD WINAPI ThreadFunc1(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освобождения таймера hWTimer

WaitForSingleObject(hWTimer, INFINITE);

// выполнение операций потоком 1

...

// Задаем следующее срабатывание через 2 мс

li.QuadPart = - (2 * 10000);

SetWaitableTimer(hWTimer,&li,0,NULL,NULL,FALSE);

}

}

// Функция потока 2

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освобождения таймера hWTimer

WaitForSingleObject(hWTimer, INFINITE);

// выполнение операций потоком 2

...

// Задаем следующее срабатывание через 2 мс

li.QuadPart = - (2 * 10000);

SetWaitableTimer(hWTimer,&li,0,NULL,NULL,FALSE);

}

}

Пример 2. Устанавливаем ожидаемый таймер, чтобы он срабатывал ежедневно в 12.00 (время перерыва на обед) и вызывал APC-функцию, которая выдает звуковой сигнал 1000 гц.

#define _WIN32_WINNT 0x0400

HANDLE hWTimer;

SYSTEMTIME st;

FILETIME ftLocal, ftUTC;

LARGE_INTEGER liUTC;

// callback функция таймера

VOID CALLBACK TimerAPCProc(LPVOID, DWORD, DWORD)

{

Beep(1000,500); // выдается звуковой сигнал

};

...

// создаем таймер с автосбросом

hWTimer = CreateWaitableTimer(NULL, FALSE, NULL);

// узнаем текущую дату/время

GetLocalTime(&st);

// если назначенный час уже наступил,

// то ставим время на завтра

if (st.wHour > 12) st.wDay++;

st.wHour = 12;

st.wMinute = 0;

st.wSecond = 0;

// преобразуем время из SYSTEMTIME в FILETIME

SystemTimeToFileTime(&st, &ftLocal);

// преобразуем местное время в UTC-время

LocalFileTimeToFileTime(&ftLocal, &ftUTC);

// преобразуем FILETIME в LARGE_INTEGER из-за

// различий в выравнивании данных

liUTC.LowPart = ftUTC.dwLowDateTime;

liUTC.HighPart = ftUTC.dwHighDateTime;

// устанавливаем таймер

SetWaitableTimer(hWTimer, &liUTC, 24*60*60*1000, TimerAPCProc, NULL, FALSE);

. . .