7.2. Взаимные исключения: установка и снятие блокировки

7.2. Взаимные исключения: установка и снятие блокировки

Взаимное исключение (mutex) является простейшей формой синхронизации. Оно используется для защиты критической области (critical region), предотвращая одновременное выполнение участка кода несколькими потоками (если взаимное исключение используется потоками) или процессами (если взаимное исключение используется несколькими процессами). Выглядит это обычно следующим образом:

блокировать_mutex(…);

критическая область

разблокировать_mutex(…);

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

Взаимные исключения по стандарту Posix объявлены как переменные с типом pthread_mutex_t. Если переменная-исключение выделяется статически, ее можно инициализировать константой PTHREAD_MUTEX_INITIALIZER:

static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;

При динамическом выделении памяти под взаимное исключение (например, вызовом mallос) или при помещении его в разделяемую память мы должны инициализировать эту переменную во время выполнения, вызвав функцию pthread_ mutex_init, как показано в разделе 7.7.

ПРИМЕЧАНИЕ

Вам может попасться код, в котором взаимные исключения не инициализируются, поскольку в реализации инициализирующая константа имеет значение 0, а статические переменные автоматически инициализируются этим значением. Однако такой код некорректен.

Следующие три функции используются для установки и снятия блокировки взаимного исключения:

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mptr);

int pthread_mutex_trylock(pthread_mutex_t *mptr);

int pthread_mutex_unlock(pthread_mutex_t *mptr);

/* Все три возвращают 0 в случае успешного завершения, положительное значение Еххх – случае ошибки */

При попытке заблокировать взаимное исключение, которое уже заблокировано другим потоком, функция pthread_mutex_lock будет ожидать его разблокирования, a pthread_mutex_trylock (неблокируемая функция) вернет ошибку с кодом EBUSY.

ПРИМЕЧАНИЕ

Если несколько процессов ожидают освобождения взаимного исключения, какой из них начнет выполняться первым? Одна из возможностей, добавленных стандартом 1003.1b-1993, заключается в установке приоритета потоков. Мы не будем углубляться в эту область, отметим лишь, что разным потокам могут быть присвоены разные значения приоритета и функции синхронизации (работающие с взаимными исключениями, блокировками чтения-записи и семафорами) будут передавать управление заблокированному потоку с наивысшим значением приоритета. Раздел 5.5 книги [3] описывает возможности планирования выполнения в Posix.1 более подробно.

Хотя мы говорим о защите критической области кода программы, на самом деле речь идет о защите данных, с которыми работает эта часть кода. То есть взаимное исключение обычно используется для защиты совместно используемых несколькими потоками или процессами данных.

Взаимные исключения представляют собой блокировку коллективного пользования. Это значит, что если совместно используемые данные представляют собой, например, связный список, то все потоки, работающие с этим списком, должны блокировать взаимное исключение. Ничто не может помешать потоку работать со списком, не заблокировав взаимное исключение. Взаимные исключения предполагают добровольное сотрудничество потоков.

Данный текст является ознакомительным фрагментом.