Мьютекс

Мьютекс - инструмент, предназначенный для решения задач синхронизации доступа к разделяемым ресурсам на основе организации взаимного исключения.

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

У мьютекса нет значения, но есть состояние открыт/закрыт. В этом отличие от семафора Дейкстры.

Init

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
  • mutex - указатель на переменную типа мьютекс.
  • attr - атрибуты мьютекса (не рассматриваем. Будет только NULL - атрибуты по умолчанию)

pthread_ функции возвращают 0, в случае успеха, и код ошибки, в случае неудачи. Init возвращает только 0.

Destroy

int pthread_mutex_destroy(pthread_mutex_t *mutex)

Завершение работы с мьютексом до освобождения динамической памяти.

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

Lock

int pthread_mutex_lock(pthread_mutex_t *mutex)

Закрывает указанный мьютекс. Если тот уже закрыт, процесс блокируется до тех пор, пока не получится закрыть мьютекс.
Если закрыть мьютекс из одной нити дважды, нить получит deadlock. (при NULL параметре в init)

Trylock

int pthread_mutex_trylock(pthread_mutex_t *mutex)

То же, что и обычный lock, но возвращает код ошибки EBUSY, если мьютекс уже закрыт.

Unlock

int pthread_mutex_unlock(pthread_mutex_t *mutex)

Освобождает указанный мьютекс. Можно сделать только из нити, занявшей его. Если попытаться из другой нити, вернётся ошибка. (при NULL в init)

Пример

Создаём 10 нитей.
Разделяемый ресурс - строка: каждая нить определяет текущую длину строки и добавляет код символа с возрастающим значением в её конец.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
 
#define N_SIZE 10
 
char str[N_SIZE + 1];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// macros from pthread.h
 
void *fThread(void *arg) {
	pthread_mutex_lock(&mutex);
	// add symbol
	int iPos = strlen(str);
	str[iPos] = 'A' + iPos;
	pthread_mutex_unlock(&mutex);
	return NULL;
}
 
int main() {
	pthread_t threads[N_SIZE];
	int i;
	
	// init array by zeros
	memset(str, 0, N_SIZE + 1);
	for (i = 0; i < N_SIZE; i++) {
		pthread_create(&threads[i], NULL, fThread, NULL);
	} 
	
	// waiting for threads end
	for (i = 0; i < N_SIZE; i++) {
		pthread_join(threads[i], NULL);
	}
	
	printf("%s\n", str);
	return 0;
}

Циклические блокировки

Барьеры

Условные переменные