为了账号安全,请及时绑定邮箱和手机立即绑定

一般而言,重入锁和概念是什么?

一般而言,重入锁和概念是什么?

我总是很困惑。有人会解释可重入在不同情况下的含义吗?以及为什么要使用可重入与非可重入?说pthread(posix)锁定原语,它们是否可重入?使用它们时应避免哪些陷阱?互斥锁是否重新进入?
查看完整描述

3 回答

?
炎炎设计

TA贡献1808条经验 获得超4个赞

使用重入锁,您可以编写一个M对资源加锁的方法,A然后M递归调用,或从已经持有on锁的代码中进行调用A

使用非重入锁,您将需要2个版本的M,一个可以锁定的版本和一个不可以锁定的版本,以及其他用于调用正确版本的逻辑。


查看完整回答
反对 回复 2019-12-10
?
ABOUTYOU

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中是顺序执行的,因此您一定要以递归方式重新锁定互斥锁。使用普通互斥锁会导致死锁。并且发明了递归互斥体来解决这个问题。



查看完整回答
反对 回复 2019-12-10
  • 3 回答
  • 0 关注
  • 866 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信