Yinelemeli muteksin ne ve neden , kabul edilen yanıtta açıklanan bu kadar karmaşık bir şey olmamalıdır.
İnternette biraz kazı yaptıktan sonra anlayışımı yazmak istiyorum.
İlk olarak, muteks hakkında konuşurken , çok iş parçacıklı kavramların da kesinlikle dahil olduğunu anlamalısınız . (muteks senkronizasyon için kullanılır. Programımda sadece 1 iş parçacığım varsa mutekse ihtiyacım yok)
İkinci olarak, normal bir muteks ve özyinelemeli bir muteks arasındaki farkı bilmelisiniz. .
APUE'den alıntı :
(Özyinelemeli bir muteks, a) Aynı iş parçacığının , önce kilidini açmadan onu birçok kez kilitlemesine izin veren bir muteks türüdür .
Temel fark, aynı iş parçacığı içinde özyinelemeli bir kilidin kilitlenmeye yol açmaması ve iş parçacığını engellememesidir.
Bu, tekrarlayıcı kilidin asla kilitlenmeye neden olmadığı anlamına mı geliyor?
Hayır, kilidi açmadan bir iş parçacığında kilitlediyseniz ve diğer iş parçacıklarında kilitlemeye çalışıyorsanız, normal muteks gibi kilitlenmeye neden olabilir.
Kanıt olarak biraz kod görelim.
- kilitlenme ile normal muteks
#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);
}
çıktı:
thread1
thread1 hey hey
thread2
ortak kilitlenme örneği, sorun yok.
- kilitlenme ile özyinelemeli muteks
Sadece bu satırı uncomment
error = pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
açıklamasını ve diğerini yorumlayın.
çıktı:
thread1
thread1 hey hey
thread2
Evet, yinelemeli muteks de kilitlenmeye neden olabilir.
- normal muteks, aynı iş parçacığı içinde yeniden kilitle
#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);
}
çıktı:
thread1
func3
thread2
Kilitlenme thread t1
, içeri func3
.
( sleep(2)
Kilitlenmenin öncelikle yeniden kilitlenmeden kaynaklandığını görmeyi kolaylaştırmak için kullanırım func3
)
- özyinelemeli muteks, aynı iş parçacığı içinde yeniden kilitle
Yine, yinelemeli muteks satırının açıklamasını kaldırın ve diğer satırı yorumlayın.
çıktı:
thread1
func3
func3 hey hey
thread1 hey hey
thread2
İçinde Kilitlenme thread t2
içinde, func2
. Görmek? func3
bitirir ve çıkar, yeniden kilitleme iş parçacığı engellemez veya kilitlenmeye yol açmaz.
Öyleyse, son soru, neden buna ihtiyacımız var?
Özyinelemeli işlev için (çok iş parçacıklı programlarda çağrılır ve bazı kaynakları / verileri korumak istiyorsunuz).
Örneğin, çok evreli bir programınız var ve A evresinde özyinelemeli bir işlev çağırıyorsunuz. Bu özyinelemeli işlevde korumak istediğiniz bazı verileriniz var, dolayısıyla muteks mekanizmasını kullanıyorsunuz. Bu işlevin yürütülmesi A evresinde sıralıdır, bu nedenle muteksi özyinelemede kesinlikle yeniden kilitlersiniz. Normal muteks kullanmak kilitlenmelere neden olur. Ve resursive mutex bunu çözmek için icat edildi.
Kabul edilen cevaptan bir örnek görün
Özyinelemeli muteks ne zaman kullanılır? .
Wikipedia yinelemeli muteksi çok iyi açıklıyor. Kesinlikle okumaya değer. Wikipedia: Reentrant_mutex