<b>#include <рthread.h></b>
<b>int pthread_mutex_init(pthread_mutex_t* mutex,</b>
<b> const pthread_mutexattr_t *mutexattr);</b>
<b>int pthread_mutex_lock(pthread_mutex_t* mutex);</b>
<b>int pthread_mutex_unlock(pthread mutex_t* mutex);</b>
<b>int pthread_mutex_destroy(pthread_mutex_t *mutex);</b>
Как обычно, в случае успешного завершения возвращается 0 и код ошибки в случае аварийного завершения, но переменная errno не задается, вам придется использовать код возврата.
Как и функции семафоров, функции мьютексов принимают указатель на предварительно объявленный объект, в данном случае типа pthread_mutex_t. Дополнительный параметр атрибутов в функции pthread_mutex_init позволяет задать атрибуты мьютекса, управляющие его поведением. По умолчанию тип атрибута — "fast". У него есть небольшой недостаток: если ваша программа попытается вызвать функцию pthread_mutex_lock для мьютекса, который уже заблокирован, программа блокируется. Поскольку поток, удерживающий блокировку, в данный момент заблокирован, мьютекс никогда не будет открыт, и программа попадает в тупиковую ситуацию. Есть возможность изменить атрибуты мьютекса так, чтобы он либо проверял наличие такой ситуации и возвращал ошибку, либо действовал рекурсивно и разрешал множественные блокировки тем же самым потоком, если будет такое же количество разблокировок в дальнейшем.
Установка атрибутов мьютекса в этой книге не рассматривается, поэтому мы будем передавать NULL в указателе на атрибуты, и использовать поведение по умолчанию. Дополнительную информацию об изменении атрибутов можно найти в интерактивном справочном руководстве к функции pthread_mutex_init.
Выполните упражнение 12.4.
Упражнение 12.4. Мьютекс потока
Далее приводится еще одна модификация исходной программы thread1.с, но значительно измененная. На этот раз вы уделите особое внимание доступу к вашим важным переменным и примените мьютекс для того, чтобы быть уверенными в том, что они доступны в любой момент времени только одному потоку. Для легкости чтения текста примера мы пропустили некоторые проверки ошибок при возвратах из мьютекса, заблокированного и открытого. В рабочем программном коде вы обязательно должны проверять эти возвращаемые значения. Далее приведен текст новой программы thread4.c.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
void *thread_function(void *arg);
pthread_mutex_t work_mutex; /* защищает work_area и time_to_exit */
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) {
perror("Mutex initialization failed");
exit(EXIT_FAILURE);
}
res pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);
printf("Input same text. Enter 'end' to finishn");
while (!time_to_exit) {
fgets (work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
while(1) {
pthread_mutex_lock(&work_mutex);
if (work_area[0] != ' ') {
pthread_mutex_unlock(&work_mutex);
sleep(1);
} else {
break;
}
}
}
pthread_mutex_unlock(&work_mutex);
printf("nWaiting for thread to finish...n");
res = pthread_join(a_thread, &thread_result);
if (res ! = 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joinedn");
pthread_mutex_destroy(&work_mutex);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
sleep(1);
pthread_mutex_lock(&work_mutex);
while(strncmp("end", work_area, 3) ! = 0) {
printf("You input %d charactersn", strlen(work_area)-1);
work_area[0] = ' ';
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
while (work_area[0] == ' ') {
pthread_mutex_unlock(&work_mutex);
sleep(1);