- •Глава 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).
- •Анонимный канал
- •Создание анонимных каналов
- •Соединение клиентов с анонимным каналом
- •Обмен данными по анонимному каналу
- •Именованный канал
- •Функция создания именованного канала
- •Функция соединения сервера с клиентом
- •Отключение сервера от клиента
- •Функция ожидания операции именованного канала
- •Функция объединения функций именованного канала
- •Подключение клиента к серверу
Функция создания вторичного потока _beginthread
Заголовочный файл: <process.h>
uintptr_t _beginthread(
IN unsigned (__stdcall *start_address)(void *),
IN unsigned stack_size,
IN void* arglist,
);
Краткое описание.
Создает поток.
Подпрограмма, которая указывается на месте первого параметра, должна содержать в конце своей работы инструкцию _endthread(); (перед return 0;)
Параметры и описание:
(1) start_address определяет начальный адрес подпрограммы, которая начинает выполнение нового потока.
(2) stack_size определяет размер стека для нового потока. Можно указать значение 0 — операционная система использует размер стека основного потока.
(3) arglist определяет cписок аргументов для передачи в новый поток. Можно указать значение NULL.
Возвращаемое значение:
Если функция завершается успешно, возвращается дескриптор созданного потока.
Если функция завершается с ошибкой, возвращается 0.
Пример использования этой функции приведен в ответе на домашнее задание про критические секции (см. ниже).
Функция создания вторичного потока _beginthreadex
Заголовочный файл: <process.h>
uintptr_t _beginthreadex(
IN void* security,
IN unsigned stack_size,
IN unsigned (__stdcall *start_address)(void *),
IN void* arglist,
IN unsigned initflag,
OUT unsigned* thrdaddr
);
Краткое описание.
Создает поток.
Подпрограмма, которая указывается на месте третьего параметра, должна содержать в конце своей работы инструкцию _endthreadex(0); (т. е. перед return 0;), где 0 — код возврата потока.
Параметры и описание:
(1) security является указателем на структуру SECURITY_ATTRIBUTES, которая определяет, может ли возвращаемый дескриптор наследоваться дочерними процессами. Если security имеет значение NULL, дескриптор не может быть унаследован. Должно быть указано NULL для приложений Windows 95.
(2) stack_size определяет размер стека для нового потока. Можно указать значение 0 — операционная система использует размер стека основного потока.
(3) start_address определяет начальный адрес подпрограммы, которая начинает выполнение нового потока.
(4) arglist определяет cписок аргументов для передачи в новый поток. Можно указать значение NULL.
(5) initflag определяет флаги, которые контролируют начальное состояние нового потока. Можно указать 0 для немедленного запуска, иначе CREATE_SUSPENDED для создания потока в приостановленном состоянии (после чего используйте ResumeThread для выполнения потока).
(6) thrdaddr определяет указатель на 32-битную переменную, которая получает идентификатор потока. Если NULL, то не используется.
Возвращаемое значение:
Если функция завершается успешно, возвращается дескриптор созданного потока.
Если функция завершается с ошибкой, возвращается 0.
Пример (C++).
Запускаем второй поток на выполнение и ждем его на протяжении времени INFINITE. Второй поток увеличивает счетчик от 0 до 10 миллионов, спит 2 секунды и завершается.
#include <iostream>
#include <windows.h>
using namespace std;
unsigned Counter = 0; /// Счетчик
unsigned __stdcall SecondThreadFunc(void* pArguments) {
cout << "Вошли во второй поток\n";
while ( Counter < 10000000 )
Counter++; /// Счетчик увеличиваем
Sleep(2000); /// Дополнительно спим
cout << "Выходим из второго потока\n";
_endthreadex(0);
return 0;
}
int main() {
setlocale(LC_ALL, "Russian"); /// Русский язык
HANDLE hThread; /// Дескриптор
unsigned threadID; /// ID потока
cout << "Создаем второй поток\n";
hThread = (HANDLE) _beginthreadex(NULL, 0, &SecondThreadFunc, NULL, 0, &threadID);
WaitForSingleObject(hThread, INFINITE); /// Ждем, сколько можем; 2 секунды точно должны ждать — в функции Sleep(2000)
cout << "Счетчик должен быть 1000000; Смотрим -> " << Counter << '\n';
CloseHandle(hThread);
return 0;
}