Мьютексы — один из важнейших механизмов синхронизации работы нескольких потоков.
Его суть в том, чтобы обеспечить одновременное выполнение тех или иных операций единственным потоком.
Для этого создаётся мьютекс с обязательно уникальным именем. В противном случае возможны ошибке в работе, как данной конкретной программы, так и другого программного обеспечения.
Поток, захвативший мьютекс, переводит его в так называемое неотмеченное состояние. После этого захват мьютекса другими потоками становится не возможным до тех пор, пока данный поток не освободит мьютекс (переведёт в отмеченное состояние).
Существуют два основных подхода для работы с мьютексами:
- В зависимости от состояния мьютекса соответствующие действия выполняются сразу. Поток, обратившийся к мьютексу, не приостанавливает своей работы;
- Поток, обратившийся к мьютексу, ожидает его освобождения и только после этого продолжает работу.
Первый подход реализуется достаточно просто.
Создаём мьютекс.
1 |
HANDLE hMutex = CreateMutex(0, true, (wchar_t*)"NAME"); |
Проверяем, не занят ли он другим потоком и, в зависимости от результата, выполняем соответствующие действия.
1 2 3 4 5 6 7 8 |
if (GetLastError() != ERROR_ALREADY_EXISTS) { //Действия, если мьютекс не занят } else { //Действия, если мьютекс занят } |
В качестве примера практического использования можно привести запрет на запуск более одного экземпляра программы.
Второй подход несколько сложнее. Мьютекс создаётся аналогичным образом, но работа с ним строится по несколько иному принципу.
В его основе лежит функция WaitForSingleObject, которая принимает два параметра: дескриптор мьютекса и время ожидания его освобождения в миллисекундах (если требуется ожидать неопределённо долго, указывается INFINITE).
Это позволяет не только перевести поток, обратившийся к мьютексу в режим ожидания, но и при необходимости, ограничить время ожидания определённым интервалом. А, по его окончании выполнить те или иные действия.
1 2 3 4 5 6 7 8 |
if (WaitForSingleObject(hMutex, 5000) == WAIT_TIMEOUT) { //Действия, если за время ожидания мьютекс не освободился } else { //Действия, если за время ожидания мьютекс освободился } |
Пример практического использования – ожидание доступа к общему ресурсу в течение определённого времени (таймаута). Если доступ получен – работаем с ресурсом, иначе — отбой.
После окончания работы с мьютексом, его необходимо освободить, чтобы другой поток мог начать работу с ним.
1 |
ReleaseMutex(hMutex); |
Когда все задачи связанные с мьютексом выполнены, его следует удалить.
1 |
CloseHandle(hMutex); |
Таким образом, с помощью мьютексов и всего нескольких простых функций, решается целый ряд задач параллельного программирования.
Добавить комментарий