Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

struct Query Queue[20]; // создание очереди

Читайте также:
  1. ABSOLUTE PARTICIPLE CONSTRUCTION
  2. AEROPLANE STRUCTURE
  3. AIRCRAFT STRUCTURE
  4. Anomalies of structure
  5. Chernyakov@yandex.ru ТЕМА: СОЗДАНИЕ МОБИЛЬНОГО ИНФОРМАЦИОННОГО РЕСУРСА
  6. Companies’ Restructuring
  7. Construction Data

Struct Query { // описание структуры запроса

LONG lClientId;

char cQueryText[256]; };

struct Query Queue[20]; // создание очереди

LONG lPreviousCount=0;

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

DWORD WINAPI ThreadFunc1(PVOID pvParam)

{ int i; DWORD dwResult=0;

struct Query Query1; // обрабатываемый запрос

struct PARAM *p= (struct PARAM *) pvParam;

while (!p->stop) {

// ожидание наличия в очереди запросов

WaitForSingleObject(hSem, INFINITE); // извлечение 1-го запроса из очереди

EnterCriticalSection(&cs);

Query1 = Queue[0];

for (i=0; i< lPreviousCount; i++)

Queue [i]= Queue [i+1];

LeaveCriticalSection(&cs);

// обработка запроса Query1 в потоке

}

return(dwResult);

}

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

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{ // содержимое функции потока 2

// аналогично потоку 1

}

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

DWORD WINAPI ThreadFunc3(PVOID pvParam)

{ // содержимое функции потока 3

// аналогично потоку 1

}

// --- Функция WinMain

int APIENTRY WinMain()

{

struct Query InQuery; // буфер для нового запроса

// Создание объекта семафор

hSem = CreateSemaphore(NULL, 0, 20, NULL);

// Создание объекта критический раздел

InitializeCriticalSection(&cs);

// получение запроса от клиента и помещение

// его в очередь

InQuery = GetQuery();

// увеличение числа запросов и счетчика на 1

if (ReleaseSemaphore(hSem, 1, &lPreviousCount))

{

EnterCriticalSection(&cs);

Queue[lPreviousCount] = InQuery;

LeaveCriticalSection(&cs);

}

else // очередь заполнена, запросу отказано

RejectQuery(InQuery);

// Удаление объектов семафор и

// критической раздел (при необходимости)

CloseHandle(hSem);

DeleteCriticalSection(&cs);

}

События

 

1.

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttrib,

BOOL fManualReset, BOOL flnitialState, LPCTSTR lpName);

 

2.

BOOL SetEvent(HANDLE hEvent);

 

3.

BOOL ResetEvent(HANDLE hEvent);

 

4.

BOOL PulseEvent(HANDLE hEvent);

 

5.

BOOL CloseHandle(HANDLE hEvent);

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

Пример 1. Два потока по очереди выполняют операции записи-чтения в блоке памяти. Используется одно событие с автосбросом.

HANDLE hEvent;

hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

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

DWORD WINAPI ThreadFunc1(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent

WaitForSingleObject(hEvent, INFINITE); // выполнение операций записи-чтения потоком 1

SetEvent(hEvent);

}

}

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

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent

WaitForSingleObject(hEvent, INFINITE); // выполнение операций записи-чтения потоком 2

SetEvent(hEvent);

}

}

 

Пример 2. Два потока параллельно выполняют операции чтения из блока памяти. Используется одно событие с ручным сбросом.

HANDLE hEvent;

hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

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

DWORD WINAPI ThreadFunc1(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent

WaitForSingleObject(hEvent, INFINITE); // выполнение операций чтения потоком 1

}

}

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

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent

WaitForSingleObject(hEvent, INFINITE); // выполнение операций чтения потоком 2

}

}

 

Пример 3. Два потока последовательно выполняют операции ввода данных и их обработки. Используются два события с автосбросом, одно в свободном состоянии, другое – в занятом.

HANDLE hEvent1, hEvent2;

hEvent1=CreateEvent(NULL, FALSE, TRUE, NULL);

hEvent2=CreateEvent(NULL, FALSE, FALSE, NULL);

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

DWORD WINAPI ThreadFunc1(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent1

WaitForSingleObject(hEvent1, INFINITE); // выполнение операций ввода данных потоком 1

// перевод события hEvent2 в свобод. состояние

SetEvent(hEvent2);

}

}

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

DWORD WINAPI ThreadFunc2(PVOID pvParam)

{

while (!p->stop)

{

// ожидание освождения события hEvent2

WaitForSingleObject(hEvent2, INFINITE); // выполнение обработки данных потоком 2

// перевод события hEvent1 в свобод. состояние

SetEvent(hEvent1);

}

}

 

 


Ожидаемые таймеры

Ожидаемые таймеры (waitable timers) — это объекты ядра, которые самостоятельно переходят в свободное состояние в определенное время или через регулярные промежутки времени.

Ожидаемые таймеры бывают двух типов: со сбросом вручную и с автосбросом. Когда освобождается таймер со сбросом вручную, возобновляется выполнение всех потоков, ожидавших этот объект, а когда в свободное состояние переходит таймер с автосбросом — лишь одного из потоков.

Функции для работы с ожидаемыми таймерами следующие:

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

...

 


Дата добавления: 2015-07-10; просмотров: 217 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
В том-то и признак настоящего искусства, что оно всегда современно, насущно, полезно» (Ф.М. Достоевский) (по произведениям 20 века).| От автора

mybiblioteka.su - 2015-2024 год. (0.022 сек.)