Средства синхронизации потоков в ОС Windows (критические секции, мьютексы, семафоры, события).


Для программ, использующих несколько потоков или процессов, необходимо, чтобы все они выполняли возложенные на них функции в нужной последовательности. В среде Windows 9x для этой цели предлагается использовать несколько механизмов, обеспечивающих слаженную работу потоков. Эти механизмы называют механизмами синхронизации. Предположим, разрабатывается программа, в которой параллельно работают два потока. Каждый поток обращается к одной разделяемой глобальной переменной. Один поток при каждом обращении к этой переменной выполняет её инкремент, а второй – декремент. При одновременной асинхронной работе потоков неизбежно возникает такая ситуация: -         первый поток прочитал значение глобальной переменной в локальную; -         ОС прерывает его, так как закончился выделенный ему квант времени процессора, и передаёт управление второму потоку; -         второй поток также считал значение глобальной переменной в локальную, декрементировал её и записал новое значение обратно; -         ОС вновь передаёт управление первому потоку, тот, ничего не зная о действиях второго потока, инкрементирует свою локальную переменную и  записывает её значение в глобальную. Очевидно, что изменения, внесённые вторым потоком, будут утеряны. Для исключения подобных ситуаций необходимо разделить во времени использование совместных данных. В таких случаях используются механизмы синхронизации, которые обеспечивают корректную работу нескольких потоков. Средства синхронизации в ОС Windows: 1) критическая секция (Critical Section) – это объект, который принадлежи процессу, а не ядру. А значит, не может синхронизировать потоки из разных процессов. Существует так же функции инициализации (создания) и удаления, вхождения и выхода из критической секции: создание – InitializeCriticalSection(…),    удаление – DeleteCriticalSection(…), вход – EnterCriticalSection(…),                выход – LeaveCriticalSection(…). Ограничения: поскольку это не объект ядра, то он не виден другим процессам, то есть можно защищать только потоки своего процесса. Критический раздел анализирует значение специальной перемен­ной процесса, которая используется как флаг, предотвращающий исполнение некоторого участка кода несколькими потоками одновременно. Среди синхронизирующих объектов критические разделы наиболее просты. 2) mutexmutable exclude. Это объект ядра, у него есть имя, а значит с их помощью можно синхронизировать доступ к общим данным со стороны нескольких процессов, точнее, со стороны потоков разных процессов. Ни один другой поток не может завладеть мьютексом, который уже принадлежит одному из по­токов. Если мьютекс защищает какие-то совместно используемые данные, он сможет выполнить свою функцию только в случае, если перед обращением к этим данным каждый из потоков будет проверять состояние этого мьютекса. Windows расценивает мьютекс как объект общего доступа, который можно пере­вести в сигнальное состояние или сбросить. Сигнальное состояние мьютекса говорит о том, что он занят. Потоки должны самостоятельно ана­лизировать текущее состояние мьютексов. Если требуется, чтобы к мьютексу могли обратиться потоки других процессов, ему надо присвоить имя. Функции: CreateMutex(имя) – создание,                  hnd=OpenMutex(имя) – открытие, WaitForSingleObject(hnd) – ожидание и занятие, ReleaseMutex(hnd) – освобождение,        CloseHandle(hnd) – закрытие. Его можно использовать в защите от повторного запуска программ. 3) семафор – semaphore. Объект ядра “семафор” используются для учёта ресурсов и служат для ограничения одновременного доступа к ресурсу нескольких потоков. Используя семафор, можно организовать работу программы таким образом, что к ресурсу одновременно смо­гут получить доступ несколько потоков, однако количество этих потоков будет ограничено. Создавая семафор, указывается максимальное количество пото­ков, которые одновременно смогут работать с ресурсом. Каждый раз, когда программа обращается к семафору, значение счетчика ресурсов семафора уменьша­ется на единицу. Когда значение счетчика ресурсов становится равным нулю, семафор недоступен. создание CreateSemaphore,                      открытие OpenSemaphore, занять WaitForSingleObject,                     освобождение ReleaseSemaphore 4событие – event. События обычно просто оповещают об окончании какой-либо операции, они также являются объектами ядра. Можно не просто явным образом освободить, но так же есть операция установки события. События могут быть мануальными (manual) и единичными (single). Единичное событие (single event) – это скорее общий флаг. Событие находится в сигнальном состоянии, если его установил какой-нибудь поток. Если для работы программы требуется, чтобы в случае возникновения события на него реа­гировал только один из потоков, в то время как все остальные потоки продолжали ждать, то используют единичное событие. Мануальное событие (manual event) — это не про­сто общий флаг для нескольких потоков. Оно выполняет несколько более сложные функции. Любой поток может установить это событие или сбросить (очистить) его. Если событие установлено, оно останется в этом состоянии сколь угодно долгое время, вне зависимости от того, сколько потоков ожидают установки этого события. Когда все потоки, ожидающие этого события, получат сообщение о том, что событие произошло, оно автоматически сбросится. Функции: SetEvent, ClearEvent, WaitForEvent. Типы событий: 1) событие с автоматическим сбросом: WaitForSingleEvent. 2) событие с ручным сбросом (manual), тогда событие необходимо сбрасывать: ReleaseEvent. Некоторые теоретики выделяют ещё один объект синхронизации: WaitAbleTimer – объект ядра ОС, который самостоятельно переходит в свободное состояние через заданный интервал времени (будильник).