- •Глава 2. Синхронизация задач с использованием api-функций и механизмов ядра.
- •§0. Объекты ядра. Основы.
- •Учет пользователей объектов ядра
- •Процесс и поток: краткая характеристика
- •Создание объекта ядра
- •Закрытие объекта ядра
- •Синхронизация объектов
- •Наследование описателей объекта
- •Именованные объекты
- •3. После этого вызова система проверяет, существует ли уже объект ядра с таким же именем. Если существует, то
- •Open-функции
- •Дублирование описателей объектов
- •1) Процесс-катализатор.
- •2) Процесс-источник.
- •3) Процесс-приемник.
- •Исходное состояние
- •1 0XF0000000 (неприм.) (неприм.)
- •1 0XF0000000 (неприм.) (неприм.)
- •Состояние после вызова DuplicateHandle
- •§1. Синхронизация задач с использованием функций ожидания.
- •Функция ожидания одного объекта
- •Функция ожидания нескольких объектов
- •Функция ожидания нескольких объектов и сообщений
- •Функция создания дочернего процесса
- •Функция завершения дочернего процесса из самого дочернего процесса
- •Функция завершения дочернего процесса из процесса родителя
- •Функция создания вторичного потока
- •Функция завершения дочернего потока из самого дочернего потока (only c)
- •Функция завершения дочернего потока из потока родителя
- •If (my_file.Is_open()) { /// Если удалось открыть
- •Функция создания вторичного потока _beginthread
- •Функция создания вторичного потока _beginthreadex
- •§2. Синхронизация задач с помощью объектов ядра «событие» (Event).
- •Функция создания события
- •Функция установки сигнального состояния события
- •Функция установки несигнального состояния события
- •Функция открытия существующего именованного объекта события
- •Дескриптор защиты (структура)
- •§3. Синхронизация задач с помощью объектов ядра «семафор» (Semaphore).
- •Функция создания семафора
- •Функция открытия семафора
- •Функция увеличения счетчика семафора на указанное количество
- •If (!ReleaseSemaphore( ghSemaphore, 1, null)) /// Если ошибка
- •§4. Синхронизация задач с помощью объектов ядра «мьютекс» (Mutex).
- •Функция создания мьютекса
- •Функция открытия существующего именованного объекта мьютекса
- •Функция освобождения владельца указанного объекта мьютекса
- •§5. Синхронизация задач с помощью объектов ядра «уведомление об изменении» (Change Notification).
- •Функция создания объекта ядра «уведомление об изменении»
- •Функция перезапуска объекта ядра «уведомление об изменении»
- •Функция остановки мониторинга дескриптора объекта ядра «уведомление об изменении»
- •§6. Синхронизация задач с помощью объектов ядра «таймер ожидания» (Waitable Timer).
- •Функция создания объекта ядра «таймер ожидания»
- •Функция активации объекта ядра «ожидаемый таймер»
- •Функция открытия объекта ядра «ожидаемый таймер»
- •1. Функцией CancelWaitableTimer().
- •2. Функцией SetWaitableTimer().
- •If (bSuccess) /// Если успешно, то
- •If (bSuccess) /// Если успешно, то
- •§7. Синхронизация задач с помощью объектов ядра «канал» (Pipe).
- •Анонимный канал
- •Создание анонимных каналов
- •Соединение клиентов с анонимным каналом
- •Обмен данными по анонимному каналу
- •Именованный канал
- •Функция создания именованного канала
- •Функция соединения сервера с клиентом
- •Отключение сервера от клиента
- •Функция ожидания операции именованного канала
- •Функция объединения функций именованного канала
- •Подключение клиента к серверу
Функция открытия объекта ядра «ожидаемый таймер»
BOOL OpenWaitableTimer(
IN DWORD dwDesiredAccess,
IN BOOL bInheritHandle,
IN LPCWSTR lpTimerName
);
Параметры и описание:
(1) dwDesiredAccess — определяет доступ к объекту. 3 варианта: TIMER_ALL_ACCESS (позволяет выполнять все действия по отношению к объекту таймера), TIMER_MODIFY_STATE (поток может использовать только функции SetWaitableTimer и CancelWaitableTimer), SYNCHRONIZE (в потоке можно использовать события функций ожидания).
(2) bInheritHandle — определяет наследование. TRUE — дочерние процессы наследуют дескриптор. FALSE — не наследуют.
(3) lpTimerName — определяет имя таймера.
Возвращаемое значение.
Если функция завершилась успешно, она возвращает TRUE, в противном случае — FALSE.
Отменить таймер можно двумя способами:
1. Функцией CancelWaitableTimer().
2. Функцией SetWaitableTimer().
Пример 1.
Абсолютный таймер, который срабатывает 23 февраля 2019 г. в 20:00, а затем каждую минуту.
#include <iostream>
#include <windows.h>
using namespace std;
void CALLBACK SpecFunc(void *lpArg, unsigned long dwTimerLowValue, unsigned long dwTimerHighValue) {
cout << "Time!\n"; /// Выводим сообщение
MessageBeep(0); /// Свистим
}
int main() {
HANDLE hColTimer; /// Создаем дескриптор объекта
SYSTEMTIME ColTime; /// Создаем структуру «дата и время»
FILETIME ftLocal_ColTime, ftUTC_ColTime;
/// Структура FILETIME содержит 64-разрядное значение (два поля типа DWORD — low и high) — число интервалов в 100 наносекунд с 1 января 1601 года (UTC).
LARGE_INTEGER liUTC_ColTime; /// 64-битное значение
bool bSuccess;
hColTimer = CreateWaitableTimer(NULL, FALSE, NULL); /// Создаем
if (hColTimer != NULL) { /// Если успешно
ColTime.wYear = 2019; /// Год — 2019
ColTime.wMonth = 2; /// Месяц — Февраль
ColTime.wDayOfWeek = 0; /// День недели — неважен
ColTime.wDay = 23; /// День месяца — 23
ColTime.wHour = 20; /// Час — 20
ColTime.wMinute = 0; /// Минуты — 0
ColTime.wSecond = 0; /// Секунды — 0
ColTime.wMilliseconds = 0; /// Миллисекунды — 0
/// Преобразуем системное время в формат времени файла. Системное время основано на всемирном координированном времени (UTC).
SystemTimeToFileTime(&ColTime, &ftLocal_ColTime);
/// Преобразуем время локального файла в время файла на основе всемирного координированного времени (UTC).
LocalFileTimeToFileTime(&ftLocal_ColTime, &ftUTC_ColTime);
liUTC_ColTime.LowPart = ftUTC_ColTime.dwLowDateTime;
liUTC_ColTime.HighPart = ftUTC_ColTime.dwHighDateTime;
bSuccess = SetWaitableTimer(hColTimer, &liUTC_ColTime, 60000, &SpecFunc, NULL, FALSE); /// Активируем таймер
/// 60000 — 60 секунд, SpecFunc — наша функция
If (bSuccess) /// Если успешно, то
/// 5 раз подряд с интервалом в 60 секунд вызываем функцию SpecFunc
for (int MyValue = 1; MyValue <= 5; MyValue += 1)
SleepEx(INFINITE, TRUE); /// Обязательно так
else /// Если ошибка, то
printf("SetWaitableTimer failed with error %d\n", GetLastError());
}
else /// Если ошибка, то
printf("CreateWaitableTimer failed with error %d\n", GetLastError());
CloseHandle(hColTimer); /// Обязательно закрываем дескриптор
cin.get(); cin.get(); /// Ввод символов — пауза перед выходом
return 0;
}
Пример 2.
Относительный таймер, который срабатывает один раз спустя 10 секунд после вызова. Далее ожидается ввод пользователя.
#include <iostream>
#include <windows.h>
using namespace std;
void CALLBACK SpecFunc(void *lpArg, unsigned long dwTimerLowValue, unsigned long dwTimerHighValue) {
cout << "Time!\n"; /// Выводим сообщение
MessageBeep(0); /// Свистим
}
int main() {
HANDLE hColTimer; /// Создаем дескриптор объекта
const unsigned long long quantum = 10 * 1000 * 1000; /// 1 квант
LARGE_INTEGER liUTC_ColTime;
liUTC_ColTime.QuadPart = -10 * quantum; /// минус означает относительное время
bool bSuccess;
hColTimer = CreateWaitableTimer(NULL, TRUE, NULL);
/// Создаем
if (hColTimer != NULL) { /// Если успешно
bSuccess = SetWaitableTimer(hColTimer, &liUTC_ColTime, 0, &SpecFunc, NULL, FALSE); /// Активируем таймер
/// SpecFunc — наша функция