我使用pthread_mutex_t进行锁定。
pthread_mutex_t m_lock;
void get1() {
cout<<"Start get 1"<<endl;
pthread_mutex_lock(&m_lock);
get2();
pthread_mutex_unlock(&m_lock);
cout<<"End get 1"<<endl;
}
void get2() {
cout<<"Start get 2"<<endl;
pthread_mutex_lock(&m_lock); // The program actually stops here because it waits to m_lock to be unlock from get1 function.
pthread_mutex_unlock(&m_lock);
cout<<"End get 2"<<endl;
}
// The thread call to run function
void* run(void* p) {
get1();
}
假设我只有一个调用run函数的线程,所以: get1锁定m_lock并调用get2,但是当它试图锁定m_lock时,它会等待锁定解锁(没有发生的事情)并且我们遇到了死锁。
我的问题是,当在get1中锁定锁的同一个线程不需要等待get2中的锁(因为它是同一个线程)时,我怎么能避免这种情况?
例如,在Java中,当您使用synchornized时,这种情况永远不会发生。
public Test implements Runnable {
public void get1() {
System.out.println("Start get 1");
synchronized (this) {
get2();
}
System.out.println("End get 1");
}
public void get2() {
System.out.println("Start get 2");
synchronized (this) {
}
System.out.println("End get 2");
}
@Override
public void run() {
get1();
}
}
这里没有死锁。
我想在我的C代码中得到相同的结果。
感谢。
答案 0 :(得分:11)
正如Kami Kaze在评论中所指出的,如果这是您的完整示例,那么它就不是问题:只有一条通向get2
的路径,而且此路径已经获得互斥;只是省略第二次获取它。
但是,一般来说,可以考虑不清楚的情况。在这种情况下,您可以制作互斥recursive/reentrant:
在计算机科学中,可重入互斥(递归互斥,递归锁定)是特殊类型的互斥(互斥)设备,可以被同一进程/线程多次锁定,而不会导致死锁。
在您的设置中,这将通过pthread_mutexattr_settype
:
pthread_mutexattr_settype(&m_lock, PTHREAD_MUTEX_RECURSIVE);
答案 1 :(得分:0)
有了这个:
pthread_mutex_lock(&m_lock);
get2();
pthread_mutex_unlock(&m_lock);
您已锁定整个get2()
。因此,在get2()
函数中再次使用相同的锁是没有意义的。
只需从get2()
删除锁定和解锁代码。
如果只有get2()
中的代码部分需要锁定,那么就可以摆脱get1()
函数的锁定和解锁。
例如,在Java中,这种情况永远不会在您使用时发生 synchornized。
在您的代码中, synchronized 区域不相互关联。因此,对于类似的比较,您需要在get2()
函数中使用不同的互斥锁。
答案 2 :(得分:0)
这称为锁定递归。
Jboss
的最后一个参数是属性struct。您可以设置属性以允许使用pthread_mutex_init
进行递归锁定。
但是,我必须在这里添加一些编辑内容。我非常强烈地相信锁定递归几乎总是一个错误。或者它将导致无法在程序生命周期的后期调试错误。
锁定操作可以被理解为表示&#34;当锁定函数返回时,由锁定保护的对象处于已知状态,并且在调用解锁函数之前该状态不会改变&#34;。这意味着如果pthread_mutexattr_settype(..., PTHREAD_MUTEX_RECURSIVE)
已经开始使用锁定修改您保护的对象,然后get1
递归该锁定,则此合约将被中断两次。首先是因为get2
在对象未处于已知状态时成功获取锁定,其次是因为在get2
认为它拥有锁定时修改了对象。
当然,我们经常会做这样的事情,但这是一种可怕的做法。重新设计您的程序以不递归锁定。执行此操作的标准方法是实现名为get1
的函数,get2_locked
获取锁定并调用get2
,而get2_locked
已知道它具有锁定并将调用{ {1}}。
答案 3 :(得分:0)
我认为get1
真的不只是获取锁并调用get2
?否则get1
会是什么意思?
如果是这种情况,您可以通过get3
函数来解决它,该函数执行get2
的主要部分(此处未显示的部分)并且不锁定。然后从get1
调用该新函数(当然也从get
调用):
void get1()
{
// Do something here
cout<<"Start get 1"<<endl;
pthread_mutex_lock(&m_lock);
get3(); // <-- Note call get3 instead here
pthread_mutex_unlock(&m_lock);
cout<<"End get 1"<<endl;
// Do something more here
}
void get2()
{
cout<<"Start get 2"<<endl;
pthread_mutex_lock(&m_lock); // The program actually stops here because it waits to m_lock to be unlock from get1 function.
get3(); // <-- Note call to get3 here
pthread_mutex_unlock(&m_lock);
cout<<"End get 2"<<endl;
}
void get3()
{
// Do the actual work of get2 here...
// Note: No locking here
}