Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Объекты Mutex



Если необходимо обеспечить последовательное использование ресурсов задачами, созданными в рамках разных процессов, вместо критических секций необходимо использовать объекты синхронизации Mutex. Свое название они получили от выражения “mutually exclusive”, что означает “взаимно исключающий”.

Также как и объект-событие, объект Mutex может находится в отмеченном или неотмеченном состоянии. Когда какая-либо задача, принадлежащая любому процессу, становится владельцем объекта Mutex, последний переключается в неотмеченное состояние. Если же задача “отказывается” от владения объектом Mutex, его состояние становится отмеченным.

Организация последовательного доступа к ресурсам с использованием объектов Mutex возможна потому, что в каждый момент только одна задача может владеть этим объектом. Все остальные задачи для того чтобы завладеть объектом, который уже захвачен, должны ждать, например, с помощью уже известных вам функции WaitForSingleObject.

Для того чтобы объект Mutex был доступен задачам, принадлежащим различным процессам, при создании вы должны присвоить ему имя (аналогично тому, как вы это делали для объекта-события).

Создание объекта Mutex

Для создания объекта Mutex вы должны использовать функцию CreateMutex, прототип которой мы привели ниже:

HANDLE CreateMutex(

LPSECURITY_ATTRIBUTES lpMutexAttributes, // атрибуты защиты

BOOL bInitialOwner, // начальное состояние

LPCTSTR lpName); // имя объекта Mutex

В качестве первого параметра (атрибуты защиты) вы можете указать значение NULL (как и во всех наших примерах).

Параметр bInitialOwner определяет начальное состояние объекта Mutex. Если он имеет значение TRUE, задача, создающая объект Mutex, будет им владеть сразу после создания. Если же значение этого параметра равно FALSE, после создания объект Mutex не будет принадлежать ни одной задаче, пока не будет захвачен ими явным образом.

Через параметр lpName вы должны передать указатель на имя объекта Mutex, для которого действуют те же правила, что и для имени объекта-события. Это имя не должно содержать символ ‘\’ и его длина не должна превышать значение MAX_PATH.

Если объект Mutex будет использован только задачами одного процесса, вместо адреса имени можно указать значение NULL. В этом случае будет создан “безымянный” объект Mutex.

Функция CreateMutex возвращает идентификатор созданного объекта Mutex или NULL при ошибке.

Возможно возникновение такой ситуации, когда приложение пытается создать объект Mutex с именем, которое уже используется в системе другим объектом Mutex. В этом случае функция CreateMutex вернет идентификатор существующего объекта Mutex, а функция GetLastError, вызыванная сразу после вызова функции CreateMutex, вернет значение ERROR_ALREADY_EXISTS XE "ERROR_ALREADY_EXISTS". Заметим, что функция создания объектов-событий CreateEvent ведет себя в данной ситуации аналогичным образом.

Освобождение идентификатора объекта Mutex

Если объект Mutex больше не нужен, вы должны освободить его идентификатор при помощи универсальной функции CloseHandle. Заметим, тем не менее, что при завершении процесса освобождаются идентификаторы всех объектов Mutex, созданных для него.

Открытие объекта Mutex

Зная имя объекта Mutex, задача может его открыть с помощью функции OpenMutex, прототип которой приведен ниже:

HANDLE OpenMutex(

DWORD fdwAccess, // требуемый доступ

BOOL fInherit, // флаг наследования

LPCTSTR lpszMutexName); // адрес имени объекта Mutex

Флаги доступа, передаваемые через параметр fdwAccess, определяют требуемый уровень доступа к объекту Mutex. Этот параметр может быть комбинацией следующих значений:

EVENT_ALL_ACCESS - указаны все возможные флаги доступа;

SYNCHRONIZE - полученный идентификатор можно будет использовать в любых функциях ожидания события.

Параметр fInherit определяет возможность наследования полученного идентфикатора. Если этот параметр равен TRUE, идентфикатор может наследоваться дочерними процессами. Если же он равен FALSE, наследование не допускается.

Через параметр lpszEventName вы должны передать функции адрес символьной строки, содержащей имя объекта Mutex.

С помощью функции OpenMutex несколько задач могут открыть один и тот же объект Mutex и затем выполнять одновременное ожидание для этого объекта.

Как завладеть объектом Mutex

Зная идентификатор объекта Mutex, полученный от функций CreateMutex или OpenMutex, задача может завладеть объектом при помощи функций ожидания событий, например, при помощи функций WaitForSingleObject или WaitForMultipleObjects.

Напомним, что функция WaitForSingleObject возвращает управление, как только идентификатор объекта, передаваемый ей в качестве параметра, перейдет в отмеченное состояние. Если объект Mutex не принадлежит ни одной задаче, его состояние будет отмеченным.

Когда вы вызываете функцию WaitForSingleObject для объекта Mutex, который никому не принадлежит, она сразу возвращает управление. При этом задача, вызвавшая функцию WaitForSingleObject, становится владельцем объекта Mutex. Если теперь другая задача вызовет функцию WaitForSingleObject для этого же объекта Mutex, то она будет переведена в сотояние ожидания до тех пор, пока первая задача не “откажется от своих прав” на данный объект Mutex. Освобождение объекта Mutex выполняется функцией ReleaseMutex, которую мы сейчас рассмотрим.

Захват объекта Mutex во владение по своему значению аналогичен входу в критическую секцию.

Освобождение объекта Mutex

Для отказа от владения объектом Mutex (то есть для его освобождения) вы должны использовать функцию ReleaseMutex:

BOOL ReleaseMutex(HANDLE hMutex);

Через единственный параметр этой функции необходимо передать идентификатор объекта Mutex. Функция возвращает значение TRUE при успешном завершении и FALSE при ошибке.

Проводя аналогию с критическими секциями, заметим, что освобождение объекта Mutex соответствует выходу из критической секции.

Рекурсивное использование объектов Mutex

Так же как и критические секции, объекты Mutex допускают рекурсивное использование. Задача может выполнять рекурсивные попытки завладеть одним и тем же объектом Mutex и при этом она не будет переводиться в состояние ожидания.

В случае рекурсивного использования каждому вызову функции ожидания должен соответствовать вызов функции освобождения объекта Mutex ReleaseMutex.

#include <windows.h>

#include <conio.h>

#include <stdio.h>

#include <clocale>

//CRITICAL_SECTION csWindowPaint;

void threadPrint(char * number){

//EnterCriticalSection(&csWindowPaint);

for (int i=1; i<10; ++i) {printf(number);}

//LeaveCriticalSection(&csWindowPaint);

//DeleteCriticalSection(&csWindowPaint);

}

DWORD WINAPI ThreadFunc1(LPVOID lpParam)

{

HANDLE hMutex = OpenMutexA(MUTEX_ALL_ACCESS, false, "SyncKey");

// WaitForSingleObject(hMutex, INFINITE);

threadPrint("Поток1-- \n");

ReleaseMutex(hMutex);

CloseHandle(hMutex);

return 0;

}

DWORD WINAPI ThreadFunc2(LPVOID lpParam)

{

HANDLE hMutex = OpenMutexA(MUTEX_ALL_ACCESS, false, "SyncKey");

// WaitForSingleObject(hMutex, INFINITE);

threadPrint("Поток2-- \n");

ReleaseMutex(hMutex);

CloseHandle(hMutex);

return 0;

}

VOID main(VOID)

{

DWORD dwThreadId, dwThrdParam = 1;

HANDLE hThread;

char *szMsg;

setlocale(LC_CTYPE, "rus");

HANDLE hMutex = CreateMutexA(NULL, false, "SyncKey");

ReleaseMutex(hMutex);

//InitializeCriticalSection(&csWindowPaint);

hThread = CreateThread(

NULL, // атрибуты безопасности по умолчанию

0, // размер стека используется по умолчанию

ThreadFunc1, // функция потока

&dwThrdParam, // аргумент функции потока

0, // флажки создания используются по умолчанию

&dwThreadId); // возвращает идентификатор потока

// При успешном завершении проверяет возвращаемое значение.

dwThrdParam = 2;

HANDLE h = CreateThread(NULL, 0, ThreadFunc2, &dwThrdParam, 0, NULL);

if ((hThread == NULL)||(h == NULL))

{

szMsg="Поток не запущен!\n";

MessageBoxA(NULL, szMsg, "Текущий процесс", MB_OK);

}

else

{

szMsg="Потоки выполнились! Нажмите клавишу.....\n";

// WaitForSingleObject(hMutex, INFINITE);

printf(szMsg);

ReleaseMutex(hMutex);

_getch();

CloseHandle(hThread);

CloseHandle(h);

CloseHandle(hMutex);

}

}





Дата публикования: 2015-10-09; Прочитано: 372 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.011 с)...