Шрифт:
Устанавливает и возвращает атрибут мьютекса
type
мьютексного атрибутного объекта, заданного параметром
attr
. Атрибут мьютекса
type
позволяет определить, будет ли мьютекс распознавать взаимоблокировку, проверять ошибки и т.д. Параметр
type
может содержать такие значения:
int
PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_NORMAL
pthread_mutexattr_gettype (const pthread_mutexattr_t * restrict attr, int *restrict type);
Самый большой интерес представляет установка атрибута, связанного с тем, каким должен быть мьютекс: закрытым или разделяемым. Закрытые мьютексы разделяются между потоками одного процесса. Можно либо объявить мьютекс глобальным, либо организовать передачу дескриптора между потоками. Разделяемые мьютексы используются потоками, имеющими доступ к памяти, в которой разме щ ен данный мьютекс. Такой мьютекс могут разделять потоки различных процессов. Принцип действия закрытого и разделяемого мьютексов показан на рис. 5.5. Если разделять мьютекс приходится потокам различных процессов, его необходимо разместить в памяти, которая является общей для этих процессов. В библиотеке POSIX определено несколько функций, предназначенных для распределения памяти между объектами с помощью отображаемых в памяти файлов и объектов разделяемой памяти. В процессах мьютексы можно использовать для защиты критических разделов, которые получают доступ к файлам, каналам, общей памяти и внешним устройствам.
Использование мьютексных семафоров для управления критическими разделами
Мьютексы используются для управления критическими разделами процессов и потоков, чтобы предотвратить возникновение условий «гонок». Мьютексы позволяют избежать условий «гонок», реализуя последовательный доступ к критическому разделу. Рассмотрим код листинга5.1. В нем демонстрируется выполнение двух потоков. Для защиты их критических разделов и используются мьютексы.
// Листинг 5.1. Использование мьютексов для защиты
// критических разделов потоков
// . . .
pthread_t ThreadA, ThreadB; pthread_mutex_t Mutex,-pthread_mutexattr_t MutexAttr;
void *task1(void *X) {
pthread_mutex_lock(&Mutex); // Критический раздел кода.
pthread_mutex_unlock(&Mutex);
return(0) ;
}
void *task2 (void *X) {
pthread_mutex_lock(&Mutex) ;
// Критический раздел кода.
pthread_mutex_unlосk (&Mu t ex) ; return(0) ;
}
int main(void) {
//...
pthread_mutexattr_init (&MutexAttr) ;
pthread_mutex_init (&Mutex, &MutexAttr) ;
//Устанавливаем атрибуты мьютекса.
pthread_create(&ThreadA, NULL, taskl, NULL) ; pthread_create(&ThreadB,NULL, task2,NULL) ;
//...
return(0) ;
}
В листинге 5.1 потоки ThreadA и ThreadB содержат критические разделы, защищаемые с помощью объекта Mutex.
В листинге 5.2 демонстрируется, как можно использовать мьютексы для защиты критических разделов процессов.
// Листинг 5.2. Использование мьютексов для зашиты
// критических разделов процессов
//...
int Rt;
pthread_mutex_t Mutexl ; pthread_mutexattr_t MutexAttr;
int main(void) {
//...
pthread_mutexattr_init (&MutexAttr); pthread_mutexattr_setpshared(
&MutexAttr,
PTHREAD_PROCESS_SHARED ) ;
pthread_mutex_init (&Mutexl, &MutexAttr) ; if((Rt = fork) == 0){
// Сыновний процесс.
pthread_mutex_lock(&Mutexl);
// Критический раздел.
pthread_mutex_unlock(&Mutexl) ;
}
else{
// Родительский процесс,
pthread_mutex_lock(&Mutexl); // Критический раздел. pthread_mutex_unlock(&Mutexl) ;
}
//.. .
return(0);
}
Рис. 5.5. Закрытые и разделяемые мьютексы
Важно отметить, что в листинге 5.2 при вызове следующей функции мьютекс инициализируется как разделяемый:
pthread_mutexattr_setpshared(&MutexAttr,PTHREAD_PROCESS_SHARED);
Установка этого атрибута равным значению PTHREAD_PROCESS_SHARED позволяет объекту Mutex стать разделяемым между потоками различных процессов. После вызова функции fork сыновний и родительский процессы могут защищать свои критические разделы с помощью объекта Mutex. Критические разделы этих процессов могут содержать некоторые ресурсы, разделяемые обоими процессами.