Що і чому рекурсивний мьютекс не повинен бути такою складною справою, описаною у прийнятій відповіді.
Я хотів би записати своє розуміння після певного копання в мережі.
По-перше, ви повинні усвідомити, що, говорячи про мьютекс , багатозначні поняття, безумовно, теж задіяні. (mutex використовується для синхронізації. Мені не потрібен mutex, якщо у моїй програмі є лише 1 потік)
По-друге, ви повинні знати різницю між нормальним і рекурсивним мьютексами .
Процитовано з APUE :
(Рекурсивний мьютекс - a) Тип мьютексу, що дозволяє одному і тому ж потоку блокувати його кілька разів, не розблокувавши попередньо.
Ключова відмінність полягає в тому, що всередині того самого потоку повторне блокування рекурсивного блокування не призводить до тупикової ситуації, ані блокування потоку.
Чи означає це, що рекузивний замок ніколи не спричиняє глухого кута?
Ні, це все одно може спричинити глухий кут як звичайний мьютекс, якщо ви зафіксували його в одному потоці, не розблокуючи, і спробуйте заблокувати в інших потоках.
Давайте розглянемо деякий код як доказ.
- нормальний мьютекс із тупиком
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t lock;
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
// error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
вихід:
thread1
thread1 hey hey
thread2
типовий приклад безвихідності, не проблема.
- рекурсивний мьютекс із тупиком
Просто розкоментуйте цей рядок
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
і прокоментуйте інший.
вихід:
thread1
thread1 hey hey
thread2
Так, рекурсивний мьютекс також може спричинити глухий кут.
- нормальний мьютекс, переблокуйте в тому ж потоці
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
pthread_mutex_t lock;
void func3(){
printf("func3\n");
pthread_mutex_lock(&lock);
printf("func3 hey hey\n");
}
void * func1(void *arg){
printf("thread1\n");
pthread_mutex_lock(&lock);
func3();
printf("thread1 hey hey\n");
}
void * func2(void *arg){
printf("thread2\n");
pthread_mutex_lock(&lock);
printf("thread2 hey hey\n");
}
int main(){
pthread_mutexattr_t lock_attr;
int error;
// error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_DEFAULT);
if(error){
perror(NULL);
}
pthread_mutex_init(&lock, &lock_attr);
pthread_t t1, t2;
pthread_create(&t1, NULL, func1, NULL);
sleep(2);
pthread_create(&t2, NULL, func2, NULL);
pthread_join(t2, NULL);
}
вихід:
thread1
func3
thread2
Тупик у thread t1
, в func3
.
(Я використовую, sleep(2)
щоб полегшити переконання, що глухий кут спочатку спричинений переблокуванням func3
)
- рекурсивний мьютекс, заблокуйте в тому ж потоці
Знову ж, розкомментируйте рекурсивний мютексний рядок і прокоментуйте інший рядок.
вихід:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
Тупик у thread t2
, в func2
. Побачити? func3
закінчує та виходить, повторне блокування не блокує нитку та не веде до глухого кута.
Отже, останнє запитання, навіщо це нам потрібно?
Для рекурсивної функції (викликається у багатопотокових програмах і ви хочете захистити деякий ресурс / дані).
Наприклад, у вас є багатопотокова програма, і ви викликаєте рекурсивну функцію в потоці A. У вас є деякі дані, які ви хочете захистити в цій рекурсивній функції, тому ви використовуєте механізм mutex. Виконання цієї функції є послідовним у потоці A, тому ви точно перезаблокуєте мьютекс у рекурсії. Використання звичайного мьютексу спричиняє тупикові ситуації. І для вирішення цього винайдений ресурсивний мьютекс .
Див. Приклад із прийнятої відповіді
Коли використовувати рекурсивний мьютекс? .
У Вікіпедії дуже добре пояснюється рекурсивний мьютекс. Безумовно, варто прочитати. Вікіпедія: Reentrant_mutex