Работа потока с несколькими критическими секциями.
Критические секции.
Критические секции используются для синхронизации потоков одного процесса. Создаются критические секции обычно в области глобальных переменных, доступные всем потокам процесса. При создании, критическая секция представляет структуру данных:
Critical_Section cs1;
Обычно состоит из следующих полей: счётчика блокировок, счётчика рекурсий, идентификатора потока, который владет критической секцией в данный момент времени.
С этими полями обычно работает ОС, пользователю там нечего делать. Для работы критической секции необходимо выполнить инициализацию:
EnterCriticalSection(&cs1) – вход в критическую секцию.
// обработка данных
LeaveCriticalSection(&cs1) – выход из критической секции.
Если поток вошёл в критическую секцию, но ещё не вышел из неё, то при попытке других потоков войти в ту же критическую секцию они будут переведены в состояние ожидания и будут ожидать до тех пор, пока поток, вошедший в критическую секцию, не выйдет из неё. Таким образом гарантируется, что фрагмент кода будет выполняться потоками последовательно.
Лекция № 12.
Если поток работает с двумя ресурсами, доступ к которым должен выпоняться последовательно, то используется несколько критических секций. При работе с несколькими критическими секциями нужно соблюдать одинаковую последовательность входа и выхода из критической секции, иначе возможны взаимные блокировки потоков, например, в приложении определены две критические секции.
Critical_Section c1;
Critical_Section c2;
// поток 1
EnterCritical_Section(&c1);
EnterCritical_Section(&c2);
LeaveCritical_Section(&c1);
// поток 2
EnterCritical_Section(&c2);
EnterCritical_Section(&c1);
LeaveCritical_Section(&c1);
LeaveCritical_Section(&c2);
Возможна взаимная блокировка.
Interlocked(…) – смотри в MSDN.
InterlockedExchange(…). С помощью этой функции изменяются значения переменной.
InterlockedExchangeAda(…). Адрес переменной изменяет содержимое переменной.
Для синхронизации с использованием объектов используются функции
WaitForSingleObject(…),
WaitForMultipleObject(…).
Синхронизация с использованием таких объектов ядра, как файл, процесс, поток, консольный ввод/вывод, оповещение об изменениях в файловой системе.
Рассмотрим синхронизацию на примере проессов потоков. Процесс поток пока выпоняется находится в занятом состоянии, когда завершается переход в свободное состояние. Синхронизация возможна по завершению.
1. Объект mutex.
CreateMutex(…). Объект ядра мьютекс хранит идентификатор потока, занявшего этот объект, поэтому освободить объект мьютекс может только тот поток, который его занял.
Объекты мьютекс допускают рекурсивный вход.
2. Объект семафор.
CreateSemaphore(…). Имеют счётчик числа ресурсов, пока этот счётчик числа – это максимально возможное число этого ресурса и текущий счётчик. Доступ к ресурсам возможен до тех пор, пока текущий счётчик больше максимального. Функции WaitForSingleObject(…), WaitForMultipleObject(…) увеличивают на 1 единицу текущий счётчик ресурса. Функция ReleaseSemaphore(…) уменьшает на 1 единицу счётчик.
Пример. Программа работает с последовательными портами, доступ к которым возможен с помощью семафоров. Максимального число ресурсов равно 4.
3. Объект событие. Используется для оповещения об окончании какой-либо операции. Существуют два типа событий: события со сбросом вручную и с автоматическим сбросом.
Сброс – это перевод события в занятое состояние, то есть в состояние non-signaled.
CreateEvent(…). В качестве параметров указываются имя события, тип и начальное состояние.