3 回答
TA贡献1808条经验 获得超4个赞
使用重入锁,您可以编写一个M
对资源加锁的方法,A
然后M
递归调用,或从已经持有on锁的代码中进行调用A
。
使用非重入锁,您将需要2个版本的M
,一个可以锁定的版本和一个不可以锁定的版本,以及其他用于调用正确版本的逻辑。
TA贡献1812条经验 获得超5个赞
递归互斥锁的内容和原因不应是公认的答案中描述的如此复杂的事情。
我想在网上进行一些探讨后写下我的理解。
首先,您应该意识到在谈论互斥时,肯定也涉及多线程概念。(互斥锁用于同步。如果程序中只有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中调用了一个递归函数。您在该递归函数中有一些要保护的数据,因此可以使用互斥锁机制。该函数的执行在线程A中是顺序执行的,因此您一定要以递归方式重新锁定互斥锁。使用普通互斥锁会导致死锁。并且发明了递归互斥体来解决这个问题。
添加回答
举报