Средства синхронизации потоков управления
Мьютексы
Функции, обслуживающие мьютексы, можно разбить на следующие группы:
-
инициализация и разрушение мьютексов: pthread_mutex_init(), pthread_mutex_destroy() (см. листинг 2.1);
#include <pthread.h> int pthread_mutex_init ( pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); int pthread_mutex_destroy ( pthread_mutex_t *mutex); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Листинг 2.1. Описание функций инициализации и разрушения мьютексов. -
захват и освобождение мьютексов: pthread_mutex_lock(), pthread_mutex_trylock(), pthread_mutex_timedlock(), pthread_mutex_unlock() (см. листинги 2.2 и 2.3);
#include <pthread.h> int pthread_mutex_lock ( pthread_mutex_t *mutex); int pthread_mutex_trylock ( pthread_mutex_t *mutex); int pthread_mutex_unlock ( pthread_mutex_t *mutex);
Листинг 2.2. Описание функций захвата и освобождения мьютексов.#include <pthread.h> #include <time.h> int pthread_mutex_timedlock ( pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
Листинг 2.3. Описание функции захвата мьютексов с ограниченным ожиданием. -
опрос и установка атрибутов мьютекса: pthread_mutex_getprioceiling(), pthread_mutex_setprioceiling() (см. листинг 2.4);
#include <pthread.h> int pthread_mutex_getprioceiling ( const pthread_mutex_t *restrict mutex, int *restrict prioceiling); int pthread_mutex_setprioceiling ( pthread_mutex_t *restrict mutex, int prioceiling, int *restrict old_ceiling);
Листинг 2.4. Описание функций опроса и установки атрибутов мьютекса. -
инициализация и разрушение атрибутных объектов мьютексов: pthread_mutexattr_init(), pthread_mutexattr_destroy() (см. листинг 2.5);
#include <pthread.h> int pthread_mutexattr_init ( pthread_mutexattr_t *attr); int pthread_mutexattr_destroy ( pthread_mutexattr_t *attr);
Листинг 2.5. Описание функций инициализации и разрушения атрибутных объектов мьютексов. -
опрос и установка атрибутов мьютекса в атрибутных объектах: pthread_mutexattr_gettype(), pthread_mutexattr_settype(), pthread_mutexattr_getpshared(), pthread_mutexattr_setpshared(), pthread_mutexattr_getprotocol(), pthread_mutexattr_setprotocol(), pthread_mutexattr_getprioceiling(), pthread_mutexattr_setprioceiling() (см. листинг 2.6).
#include <pthread.h> int pthread_mutexattr_gettype ( const pthread_mutexattr_t *restrict attr, int *restrict type); int pthread_mutexattr_settype ( pthread_mutexattr_t *attr, int type); int pthread_mutexattr_getpshared ( const pthread_mutexattr_t *restrict attr, int *restrict pshared); int pthread_mutexattr_setpshared ( pthread_mutexattr_t *attr, int pshared); int pthread_mutexattr_getprotocol ( const pthread_mutexattr_t *restrict attr, int *restrict protocol); int pthread_mutexattr_setprotocol ( *attr, int protocol); int pthread_mutexattr_getprioceiling ( const pthread_mutexattr_t *restrict attr, int *restrict prioceiling); int pthread_mutexattr_setprioceiling ( pthread_mutexattr_t *attr, int prioceiling);
Листинг 2.6. Описание функций опроса и установки атрибутов мьютекса в атрибутных объектах.
Мы не будем детально описывать каждую из перечисленных выше функций (хотя бы потому, что дисциплина работы с атрибутами и атрибутными объектами та же, что и для потоков управления ), но коснемся лишь отдельных, специфических аспектов.
Сразу после инициализации функцией pthread_mutex_init() мьютекс, разумеется, оказывается свободным. Разрушить функцией pthread_mutex_destroy() можно только инициализированный, свободный мьютекс.
Для инициализации статически описанных мьютексов с подразумеваемыми значениями атрибутов целесообразно воспользоваться макросом PTHREAD_MUTEX_INITIALIZER. Эффект будет тем же, что и после вызова pthread_mutex_init() с пустым указателем в качестве значения аргумента attr, только без накладных расходов на проверку корректности атрибутного объекта.
В стандарте POSIX-2001 тип pthread_mutex_t трактуется как абстрактный, со скрытой структурой и даже без методов для присваивания и сравнения на равенство, а попытки обойти их отсутствие за счет применения операций с областями памяти, естественно, обречены на неудачу поскольку, согласно стандарту, для синхронизации должны использоваться сами объекты- мьютексы, а не их копии. Это "развязывает руки" операционной системе в использовании доступных аппаратных возможностей при реализации мьютексов, делая ее максимально эффективной.
У инициализированного мьютекса имеется четыре атрибута:
- тип (обслуживается функциями pthread_mutexattr_gettype() и pthread_mutexattr_settype() );
- верхняя грань приоритетов выполнения (функции pthread_mutex_getprioceiling(), pthread_mutex_setprioceiling(), pthread_mutexattr_getprioceiling(), pthread_mutexattr_setprioceiling() );
- протокол ( pthread_mutexattr_getprotocol(), pthread_mutexattr_setprotocol() );
- признак использования несколькими процессами ( pthread_mutexattr_getpshared(), pthread_mutexattr_setpshared() ).
Мы уже отмечали важность эффективной реализации для средств синхронизации потоков управления. Вероятно, по этой причине в число атрибутов не включен идентификатор потока -владельца, поскольку его нужно устанавливать и хранить.