Это механизм, который позволяет потокам синхронизировать доступ к ресурсам. Для синхронизации Win32 исп-ся 2 класса методов: 1) Использование критических секций, 2) Использование ф-ий ожидание.
Любой объект синхронизации м/б в значащем или не значащем состоянии.
Ф-ия ожидания переведет поток в состояние ожидания, если требуемый объект занят; и выведетпоток из состояния ожидания, если объект синхронизации перейдет из незначащего состояния в значащее.
Сущ-ет 3 вида ф-ии ожидания:
1. Ф-ия ожидания одного объекта.
2. Ф-ия множественного объекта.
3. Ф-ия тревожного ожидания.
Ф-ия ожидания не возвращает управление до тех пор, пока не будет достигнут критерий, который указан в вызове ф-ии; когда вызывается ф-ия ожидания она проверяет находится ли объект в доступном состоянии. Если объект недоступен, то поток переводится в состояние ожидания до тех пор, пока объект не станет доступным.
Ф-ия ожидания одного объекта.
DWORD WaitForSingleObject(
HANDLE hHandle, // handle of object to wait for – какой объект ждать
DWORD dwMilliseconds // time-out interval in milliseconds — сколько ждать
);
Для второго параметра допустимы два значения: 0 – ф-ия не ждет, INFINITE – ждать бесконечно.
Ф-ия возвращает управление в случае если: 1) указанный объект перешел в свободное состяние 2) производит ожидание другого объекта синхронизации.
Ожидание мн-ва объектов.
DWORD WaitForMultipleObjects(
DWORD nCount, // сколько объектов синхронизации ждать
CONST HANDLE *lpHandles, // какие объекты
BOOL bWaitAll, // каким-образом ф-ия реагирует на освобождение объекта синхронизации
DWORD dwMilliseconds // ждать всех. Если TRUE, то ждать пока все объекты не освободятся. Иначе ждать любого одного
);
Тревожное ожидание.
— SignalObjectAndWait(…)
— WaitForMultipleObjects(…)
При выполнении каких-либо действий пользователя (нажатие клавиш, мыши) и в уже рассмотренных случаях.
Объект синхронизации.
Это объект, чей HANDLE м/б указан в вызове ф-ии ожидания. К таким объектам относятся:
1. События 2.Мьютекс
3. Семафоры 4. Ожидаемые таймеры
5. Потоки 6. Процессы
Описатели объектов синхронизации д/б доступны более чем одному потоку для того, чтобы обеспечить синхронизацию.
1. События уведомляют один ил более поток состояния, что произошло некоторое событие
2. Мьютекс в каждый момент времениможет принадлежать только одному потоку, позволяя потокам координировать доступ к разделяемым ресурсам.
3. Задача семафоров – ограничить кол-во потоков, имеющих доступ к разделяемому ресурсу\
4. Таймеры ожидания уведомляют один или более потоков о отм, что указанное время ожидания истекло.
Ф-ии ожидания и синхронизируемые объекты.
Ф-ия ожидания перед возвратом может изменить состояние объекта синхронизации; ограничение только для тех объектов, чье состояние перешло в значение свободного состояния.
Для семафоров: счетчик семафоров уменьшается на единицу.
Состояние мьютекса, событий с автосбросом, состояние объекта синхронизации устанавливается свободным.
Для ожидаемых таймеров: состяние устанавливается в свободное.
Состояние потоков и событий со сбросом вручную не изменяется.
Синхронизация потоков при помощи критич. секций.
VOID InitializeCriticalSection(& cs); — инициализация критических секций.
В каждом из потоков д/б использованы две ф-ии.
1. EnterCriticalSection(& cs);
2. LeaveCriticalSection(& cs);
VOID DeleteCriticalSection(& cs); — уничтожает критич. секцию.
Механизм работы с критич. секциями:
1. Определить переменную типа CRITICAL_SECTION.
2. Поинициализировать критич. секцию.
3. В каждом из потоков, использующих защищаемый ресурс непосредственно перед использованием вызвать ф-ию EnterCriticalSection.
4. Сразу после завершение критического участка кода, вызвать ф-ию LeaveCriticalSection().
5. После этого удалить критическую секцию.
Когда первый из потоков достигаеткритической секции, то ОС разрешает ему выполняться. Когда он вытесняется другим потоком и в другом потоке, упр-е доходит до вызова EnterCriticalSection(), ОС видит, что критич. секция уже используется и переводит поток в состяние ожидания.
Пример: использование критических секций. Создаются 2 потока.
DWORD A[1000];
CRITICAL_SECTION cs;
int WINAPI WinMain(…) {
HANDLEHThread[2];
InitializeCriticalSection(&cs);
hThread[0] = CreateThread(…, Thread1, …);
hThread[1] = CreateThread(…, Thread2, …);
WaitForMultipleObjects( 2, hTread, TRUE, INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
DeleteCriticalSection(&cs);
}
// Ф-ия потока
DWORD WINAPI Thread(LPVOID param) {
EnterCriticalSection(&cs);
for(int i=0; i<1000; i++)
A[i] = i*100;
LeaveCriticalSection(&cs);
return 0;
}
// Реализация второго потока аналогична.
Работа примера происходит сл. о.:
В каждом из потоков при помощи вызова ф-ии EnterCriticalSection() Проверяется свободна или нет критич. секция; если она свободна, то поток продолжает выполнеие, если она занята, топ потк переходит в сост. ожидания. После вызова EnterCriticalSection() гарантируется, что в каждый момент времени доступ к критическому уч-ку кода будет осуществлять только один поток.
Для того чтобыуказать, что обработка критич. участка завершена, и что др. поток может начать использовать этот участок, исп-ся ф-ия LeaveCriticalSection().
Синхронизация процессов при помощи мютексов.
Мютекс представляет собой объект ядра, имеющий свое собственное имя и предназначенный для синхронизации потоков в различных процессах. По технологии работы мьютекс очень похож на критич. секцию:
Вызвать ф-ию для создания мютекса
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // pointer to security attributes
BOOL bInitialOwner, // начальный владелец
LPCTSTR lpName // pointer to mutex-object name );
bInitialOwner == TRUE означает. что объект, который создал мьютекс явл-ся его владельцем; если FALSE, то он свободен и его владельцем будет тот, кто первым его захватит.
lpName – текстовая строка. которая указывает имя мютекса.
В кач-ве ф-ии, описывающей мютекс м/б использована ф-ия OpehMutex(), но чаще исп-ся CreateMutex() – если мьютекс не создан, то он создается.
Для того, чтобы определить возможность входа в критич. уч-к кода, исп-ся одна из ф-ий ожидания; в качестве HANDLE передается HANDLE мьютекса. В случае ожидания ф-ия может вернуть дополнительно одно значение WAIT_ABANDONED. Это означает, что мьютекс был освобожден (стал доступен) в рез-те завершения процесса, захватившего мьютекс без вызова ф-ии ReleaseMutex(). В подавляющем большинстве случаев подобное значение сигнализирует об ошибке.
После использования мьютекса, его нужно освободить вызовом ф-ии:
BOOL ReleaseMutex( HANDLE hMutex ); // handle of mutex object
Затем объект синхронизации мьютекс д/б уничтожен вызовом ф-ии;
BOOL CloseHandle( HANDLE hObject ); // handle to object to close
Пример: использование мьютекса
// Ф-ия потока, которая будет использовать мьютекс
VOID WINAPI F1(…) {
HANDLE h;
h = CreateMutex(NULL, TRUE, “M1”);
switch(WaitForSingleObject(h, INFINITE)) {
case WAIT_OBJECT_0 T:
BeginProcess();
break;
case WAIT_ABANDONED:
CloseHandle(h);
return;
}
ReleaseMutex(h);
CloseHandle(h);
}
