Apa dan mengapa mutex rekursif bukanlah hal yang rumit seperti yang dijelaskan dalam jawaban yang diterima.
Saya ingin menuliskan pemahaman saya setelah menggali di internet.
Pertama, Anda harus menyadari bahwa ketika berbicara tentang mutex , konsep multi utas pasti terlibat juga. (mutex digunakan untuk sinkronisasi. Saya tidak perlu mutex jika saya hanya memiliki 1 utas di program saya)
Kedua, Anda harus mengetahui perbedaan antara mutex normal dan mutex rekursif .
Dikutip dari APUE :
(Mutex rekursif adalah a) Jenis mutex yang memungkinkan utas yang sama menguncinya beberapa kali tanpa membukanya terlebih dahulu.
Perbedaan utamanya adalah bahwa dalam utas yang sama , mengunci kembali kunci rekursif tidak menyebabkan kebuntuan, tidak juga memblokir utas.
Apakah ini berarti bahwa gembok berulang tidak pernah menyebabkan kebuntuan?
Tidak, itu masih dapat menyebabkan kebuntuan seperti mutex biasa jika Anda telah menguncinya di satu utas tanpa membukanya, dan mencoba menguncinya di utas lain.
Mari kita lihat beberapa kode sebagai bukti.
- mutex normal dengan kebuntuan
#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_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);
}
keluaran:
thread1
thread1 hey hey
thread2
contoh kebuntuan umum, tidak masalah.
- mutex rekursif dengan kebuntuan
Hapus saja baris ini
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
dan komentari baris lainnya.
keluaran:
thread1
thread1 hey hey
thread2
Ya, mutex rekursif juga bisa menyebabkan kebuntuan.
- mutex normal, kunci kembali di utas yang sama
#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_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);
}
keluaran:
thread1
func3
thread2
Jalan buntu thread t1
, masuk func3
.
(Saya gunakan sleep(2)
untuk mempermudah melihat bahwa kebuntuan pertama-tama disebabkan oleh penguncian kembali func3
)
- mutex rekursif, kunci kembali di utas yang sama
Sekali lagi, hapus komentar pada baris mutex rekursif dan komentari baris lainnya.
keluaran:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
Jalan buntu thread t2
, masuk func2
. Lihat? func3
selesai dan keluar, penguncian ulang tidak menghalangi utas atau menyebabkan kebuntuan.
Jadi, pertanyaan terakhir, mengapa kita membutuhkannya?
Untuk fungsi rekursif (disebut dalam program multi-utas dan Anda ingin melindungi beberapa sumber daya / data).
Misalnya Anda memiliki program multi utas, dan memanggil fungsi rekursif di utas A. Anda memiliki beberapa data yang ingin dilindungi dalam fungsi rekursif itu, jadi Anda menggunakan mekanisme mutex. Eksekusi fungsi itu berurutan di utas A, jadi Anda pasti akan mengunci kembali mutex dalam rekursi. Gunakan mutex normal menyebabkan kebuntuan. Dan mutex resursif diciptakan untuk mengatasi ini.
Lihat contoh dari jawaban yang diterima
Kapan menggunakan mutex rekursif? .
Wikipedia menjelaskan mutex rekursif dengan sangat baik. Layak untuk dibaca. Wikipedia: Reentrant_mutex