Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка к лабораторным работам (рус).doc
Скачиваний:
3
Добавлен:
15.11.2018
Размер:
353.79 Кб
Скачать

2.3.2. Мьютексы

Развитием идеи критической секции стал объект ядра мьютекс (mutual exclusion). Его основное отличие заключается в том, что он позволяет организовать взаимоисключающий доступ к единственному ресурсу потокам, которые принадлежат разным процессам. Кроме того, при использовании этого объекта можно задать максимальное время ожидания доступа к ресурсу. С помощью мьютекса, как правило, защищают блоки памяти, к которым обращаются множество потоков.

Основными элементами мьютекса являются счетчик числа пользователей, счетчик рекурсии и идентификатор потока. Последний определяет, какой поток захватил мьютекс, а счетчик рекурсий – сколько раз. Для мьютекса характерны следующие правила:

  • если его идентификатор потока равен 0, мьютекс не захвачен ни одним из потоков:

  • если идентификатор потока не равен 0, мьютекс захвачен одним из потоков и находится в занятом состоянии;

Для использования объекта-мьютекса один из процессов должен сначала создать его вызовом функции :

HANDLE CreateMutex(

LPSECURITY_ATTRIBUTES lpMutexAttributes,

BOOL bInitialOwner,

LPCTSTR lpName

);

где lpMutexAttributes – указатель на структуру защиты. Если он установлен в NULL, устанавливается защита по умолчанию. В противном случае необходимо создать структуру SECURITY_ATTRIBUTES, рассмотренную в лекциях, посвященных процессам.

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

LpName - указатель на строку символов, определяющую оригинальное имя мьютекса.

Любой процесс может получить описатель существующего объекта "мьютекс", вызвав функцию:

HANDLE OpenMutex(

DWORD, dwDesiredAccess,

BOOL bInheritHandle,

LPCTSTR lpName

);

где dwDesiredAccess параметр обычно устанавливается в MUTEX_ALL_ACCESS, обеспечивая доступ к всем флагам мьютекса.

Поток получает доступ к разделяемому ресурсу, вызывая одну из Wait-функций (которые мы рассмотрим в конце лекции), передавая ей описатель мьютекса, который охраняет этот ресурс. Wait-функций проверяет у мьютекса идентификатор потока. Если его значение не равно 0, мьютекс занят, и вызывающий поток переходит в режим ожидания. При этом система следит за объектом, и когда его идентификатор потока обнуляется, записывает в него идентификатор ждущего потока, после чего ждущий поток становится планируемым. Для мьютекса сделано одно исключение: если поток, который перевел мьютекс в режим ожидания снова вызывает Wait-функцию, то система продолжает планировать выполнение потока, а счетчик рекурсии увеличивается на 1. Такое исключение не действует больше ни на один объект операционной системы.

После завершения работы, мьютекс необходимо освободить. Это возможно при помощи функции:

BOOL ReleaseMutex(

HANDLE hMutex

);

Эта функция уменьшает счетчик рекурсии в мьютексе на 1. Таким образом, если поток несколько раз обращался к мьютексу, то для его освобождения он должен выполнить столько же раз функцию ReleaseMutex.

Если программа не нуждается больше в мьютексе, она вызывает функцию

BOOL CloseHandle( HANDLE hObject );

которая закрывает описатель переданного объекта. Данная функция не уничтожает объект, если он используется еще каким-либо потоком, а лишь делает его недоступным этому потоку. Однако, если число пользователей объекта равно 0, он уничтожается.