- •Глава 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).
- •Анонимный канал
- •Создание анонимных каналов
- •Соединение клиентов с анонимным каналом
- •Обмен данными по анонимному каналу
- •Именованный канал
- •Функция создания именованного канала
- •Функция соединения сервера с клиентом
- •Отключение сервера от клиента
- •Функция ожидания операции именованного канала
- •Функция объединения функций именованного канала
- •Подключение клиента к серверу
Функция создания вторичного потока
HANDLE CreateThread(
IN PSECURITY_ATTRIBUTES psAttr,
IN DWORD cbStack,
IN PTHREAD_START_ROUTINE pfnStartAddr,
IN PVOID pvParam,
IN DWORD fdwCreate,
IN PDWORD pdwThreadID
);
Функция завершения дочернего потока из самого дочернего потока (only c)
В C++ не требуется вызов данной функции. В C вызов этой функции осуществляется в конце функции потока, перед возвратом (перед return 0;).
void ExitThread(
IN DWORD dwExitCode /// Код возврата
);
Функция завершения дочернего потока из потока родителя
Функция обычно вызывается в потоке-родителе, который создал дочерний поток.
BOOL TerminateThread(
IN HANDLE hThread, /// Handle
IN DWORD dwExitCode /// Код возврата
); /// TRUE, если успешно, иначе FALSE
Краткое описание.
Система выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Поэтому он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.
Параметры и описание:
(1) psAttr является указателем на структуру SECURITY_ATTRIBUTES. Если Вы хотите, чтобы объекту ядра «поток» были присвоены атрибуты защиты по умолчанию, передайте NULL.
(2) cbStack определяет размер адресного пространства потока. Каждому потоку выделяется отдельный стек. Если указано нулевое значение, CreateThread создает стек для нового потока, используя информацию, встроенную компоновщиком в EXE-файл.
(3) pfnStartAddr определяет указатель на определяемую приложением функцию, которая будет выполняться потоком.
(4) pvParam определяет указатель на переменную для передачи в поток (переменная может принимать числовое значение).
(5) fdwCreate определяет дополнительные флаги, управляющие созданием потока. Может принимать 0 (поток запускается сразу после создания) или CREATE_SUSPENDED (0x00000004; поток создается в приостановленном состоянии и не запускается до тех пор, пока не будет вызвана функция ResumeThread).
(6) pdwThreadID определяет указатель на переменную, которая получает идентификатор потока. Если этот параметр равен NULL, идентификатор потока не возвращается (в Windows 95/98 это приведет к ошибке).
Возвращаемое значение.
Если функция завершается успешно, возвращаемое значение является дескриптором нового потока.
Если функция завершается с ошибкой, возвращаемое значение равно NULL.
Пример (C++).
Программа создает поток, который открывает файл и записывает в него строку «Hello, world! Param: » и значение измененной в этом потоке глобальной переменной.
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
int MY_PARAM = 1; /// Глобальная переменная
DWORD WINAPI SecondThread(PVOID pvParam) {
/// Выполняется обработка
MY_PARAM = MY_PARAM + 4;
ofstream my_file;
my_file.open("spec_file.txt"); /// Открываем файл
If (my_file.Is_open()) { /// Если удалось открыть
my_file << "Hello, world! Param: " << MY_PARAM;
my_file.close(); /// Закрываем файл
}
return 0;
}
int main() {
/// Подготовка
int x = 0;
DWORD dwThreadId;
/// Создаем новый поток
HANDLE hThread = CreateThread(NULL, 0, SecondThread, (PVOID) &x, 0, &dwThreadId);
/// Даем 5 с на выполнение
WaitForSingleObject(hThread, 5000);
/// Закрываем описатель этого потока
CloseHandle(hThread);
/// В итоге наш поток закончил работу
return 0;
}
Дополнительная информация.
Если вы пользуетесь небезопасными в многопоточной среде функциями, то должны создавать потоки библиотечной функцией _beginthreadex.
Функция _beginthreadex существует только в многопоточных версиях библиотеки C/C++. Связав проект с однопоточной библиотекой, Вы получите от компоновщика сообщение об ошибке «unresolved external symbol».
_beginthreadex функция позволяет лучше контролировать способ создания потока, чем _beginthread. Есть и другие различия, но лучше всего использовать функцию _beginthreadex.