通常情况下,如果一个task1持有锁a,想要获得锁B,而另一个task2已经获得了锁B,正在等待被task1持有的锁a,这将导致死锁。
但是当涉及到pthread_mutex_timmedlock时,它会在指定的超时之后尝试互斥锁或超时。
我遇到了死锁场景,我试图采取定时锁,它最终会超时,这让我感到困惑。
edit:通过更好的设计可以避免死锁,这就是我最终所做的,我确保获得互斥锁的顺序相同,以避免死锁但问题仍然是,如果死锁可以避免,因为我选择了timelock
谁能给我解释一下这种行为?
编辑:附加示例代码以使场景更清晰(实际任务相当复杂,运行到数千行)
T1pthread_mutex_lock(&lockA);
//call some API, which results in a lock of m2
pthread_mutex_lock(&lockB);
//unlock in the order
pthread_mutex_unlock(&lockB);
pthread_mutex_unlock(&lockA);
T2 pthread_mutex_lock(&lockB);
//call some API, which results in locking m1
pthread_mutex_timedlock(&lockA,<10 sec>);
崩溃出现在T2的上下文中,bt:
Program terminated with signal 6, Aborted.
#0 0x57edada0 in raise () from /lib/libc.so.6
(gdb) bt
#0 0x57edada0 in raise () from /lib/libc.so.6
#1 0x57edc307 in abort () from /lib/libc.so.6
#2 0x57ed4421 in __assert_fail () from /lib/libc.so.6
#3 0x57bb2a7c in pthread_mutex_timedlock () from /lib/libpthread.so.0
我跟踪错误到以下
pthread_mutex_timedlock: Assertion `(-(e)) != 35 || (kind != PTHREAD_MUTEX_ERRORCHECK_NP && kind != PTHREAD_MUTEX_RECURSIVE_NP)' failed.
在glibc源代码pthread_mutex_timedlock()
中,这个断言是这样的:
int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
__lll_private_flag (FUTEX_LOCK_PI,
private), 1,
abstime);
if (INTERNAL_SYSCALL_ERROR_P (e, __err))
{
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT)
return ETIMEDOUT;
if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
|| INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)
{
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
|| (kind != PTHREAD_MUTEX_ERRORCHECK_NP
&& kind != PTHREAD_MUTEX_RECURSIVE_NP));
/* ESRCH can happen only for non-robust PI mutexes where
the owner of the lock died. */
assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH
|| !robust);
e == EDEADLK
和kind
可能是PTHREAD_MUTEX_ERRORCHECK_NP
或PTHREAD_MUTEX_RECURSIVE_NP
。另一件要注意的事情是,超时是在这个检查之前处理的,也就是说,你没有达到超时。
在内核中是futex_lock_pi_atomic()
返回EDEADLK代码:
/*
* Detect deadlocks.
*/
if ((unlikely((curval & FUTEX_TID_MASK) == vpid)))
return -EDEADLK;
/*
上面的代码比较了已经锁定互斥锁的线程的TID和试图获取互斥锁的线程的TID。如果它们是相同的,则表明线程正在尝试获取它已经获得的互斥锁。
首先,timeout指定的时间是多少?它大吗?
pthread_mutex_timmedlock在三种情况下失败1>检测到死锁条件或当前线程已经拥有互斥锁。2>无法获取互斥锁,因为已经超过了互斥锁的最大递归锁数。3>互斥锁指定的值不指向已初始化的互斥锁对象。
是您的代码受到上述任何一种影响。
代码片段也可以帮助我们清楚地看到问题。