2011-09-07 82 views
2

典型情况下,如果task1持有锁A想要取得锁B,而另一个task2取得了锁B并且正在等待task1持有的锁A,则会导致死锁。pthread_mutex_timedlock和死锁

但是,当涉及到pthread_mutex_timedlock时,它将在指定的超时后尝试互斥锁或超时。

我碰到了死锁的情况,我试图采取定时锁,最终会超时,这让我很困惑。

编辑:死锁可以通过具有更好的设计,这是我落得这样做,我确信,采取互斥锁的顺序是一样的,避免死锁 但问题仍然开放,这就是如果要避免可以避免死锁,因为我选择了timedlock

有人能解释我这种行为吗?

编辑:附加的样本代码,使场景更加清晰(真正的任务是相当复杂的,并运行到千行)

T1

pthread_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. 
+0

很难说没有看到任何代码。 –

+0

我增加了一些信息。希望有帮助 – rajshenoy

+0

也许我错误地理解了你的问题,但是我不清楚你是否理解超时是等待*获得锁的时间,而不是实际持有锁的时间。这是你问题的根源还是我误解了你对这个问题的多次编辑所说的话? – Duck

回答

2

在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 == EDEADLKkind或者是PTHREAD_MUTEX_ERRORCHECK_NPPTHREAD_MUTEX_RECURSIVE_NP。另一件需要注意的是超时在这个检查之前被处理,即你没有超时。

在内核是futex_lock_pi_atomic()返回EDEADLK代码:

/* 
    * Detect deadlocks. 
    */ 
if ((unlikely((curval & FUTEX_TID_MASK) == vpid))) 
     return -EDEADLK; 

/* 

上面一块已锁定互斥并且尝试获取该互斥的线程的TID的线程的TID进行比较。如果它们相同,则表明线程正试图获取它已获取的互斥体。

+0

是它的e = EDEADLK,互斥量是PTHREAD_MUTEX_RECURSIVE_NP。这是否意味着linux无法区分正常与时间?我唯一担心的是死锁情况在超时后放弃尝试锁定时会自动解决,为什么断言? – rajshenoy

+0

更新了我的答案。 –

+0

我认为这样做更有意义。非常感谢 – rajshenoy

0

首先究竟是什么时候了规定的时间的?它大吗?

pthread_mutex_timedlock在三种情况下失败 1>检测到死锁条件或当前线程已拥有该互斥锁。 2>互斥体无法获取,因为超过了互斥锁的递归锁的最大数量。 3>互斥体指定的值不引用已初始化的互斥体对象。

是您的代码遭受上述任何一种情况。

此外代码snipet可能有助于清除事情,为我们看到的问题。

+0

是的,指定的时间是几秒(10秒)。死锁是否取决于超时值?我找不到任何参考。我也检查过,并且互斥从未被递归地采用。我很难粘贴代码片段,因为这两个任务都非常复杂。但在通过GDB查看任务回溯后,我清楚这是典型的死锁情况,除了它是一个定时锁。 – rajshenoy

+0

给了我们一个示例代码片段与相同的情况。 –