我有一个在Linux上运行的多线程程序,有时如果我对它运行g堆栈,就会有一个线程在等待锁很长时间(比如说,2-3分钟),
线程2(线程0x5e502b90 (LWP 19853)): __kernel_vsyscall ()中的0x40000410 __lll_lock_wait ()中的10x400157b9来自/lib/i 686/nosegneg/libp线程.so.0 2 0x40010e1d来自/lib/i 686/nosegneg/libp线程.so.0的_L_lock_981 () 3 0x40010d3b来自/lib/i 686/nosegneg/libp线程.so.0的pthread_mutex_lock () ..。
我检查了其余的线程,它们都没有使用这个锁,但是过了一段时间,这个线程(LWP 19853)可以成功地获得这个锁。
应该有一个线程已经获得了这个锁,但是我没有找到它,我有遗漏什么吗?
编辑:pthread_mutex_t的定义:
类型胡枝子结合 { 结构__pthread_mutex_s { int __lock; 无符号int __count; int __owner; /*类必须在结构中保持此位置以保持二进制兼容性。*/ int __kind; 无符号int __nusers; 推广并{ int __spins;__pthread_slist_t __list;}; } __data; char _size[_SIZEOF_PTHREAD_MUTEX_T]; 长int __align; } pthread_mutex_t;
有一个成员"__owner",它是线程的id,它现在持有互斥锁。
发布于 2012-07-09 09:47:16
2-3分钟的声音听起来很大,但是如果你的系统负载很重,那就不能保证你的线程在另一个线程打开互斥锁后立即苏醒。因此,在您正在查看锁的那一刻,可能就没有线程(不再)持有锁了。
Linux互斥锁分两个阶段工作。大致如下:
int值上有一个原子CAS操作,以查看是否可以立即锁定互斥体。int地址的int系统调用传递给内核。然后,解锁操作包括将值更改为初始值(通常为0),并执行futex_wake系统调用。内核然后查看是否有人在同一个地址上注册了futex_wait调用,并恢复调度队列中的线程。哪个线程真正被唤醒,什么时候取决于不同的事情,特别是启用的调度策略。不能保证线程按所放置的顺序获得锁。
发布于 2012-07-09 13:10:46
默认情况下,Mutexe不跟踪锁定它们的线程。(至少我不知道这种事)
有两种方法可以调试这种问题。一种方法是记录每一个锁并解锁。在每个线程创建中,您都会记录创建的线程id的值。锁定任何锁后,立即记录线程id和锁定的锁的名称(您可以使用文件/行进行此操作,也可以为每个锁分配一个名称)。在打开锁之前再登录一次。
如果您的程序没有几十个线程或更多线程,这是一个很好的方法。在那之后,日志开始变得无法管理。
另一种方法是将您的锁封装在一个类中,该类将线程id存储在锁对象中的每个锁之后。您甚至可以创建一个全局锁注册表来跟踪这一点,您可以在需要时打印出来。
类似于:
class MyMutex
{
public:
void lock() { mMutex.lock(); mLockingThread = getThreadId(); }
void unlock() { mLockingThread = 0; mMutex.unlock(); }
SystemMutex mMutex;
ThreadId mLockingThread;
};这里的关键是-不要在发布版本中实现这些方法中的任何一个。全局锁定日志或锁状态的全局注册表都会创建一个单独的全局资源,该资源本身将成为处于锁定争用中的资源。
发布于 2012-07-09 08:53:02
POSIX API不包含这样做的函数。
在某些平台上,实现也可能不允许这样做。
例如,锁可以使用原子变量,锁定时设置为1。获得它的线程不必在任何地方写入其ID,因此没有任何函数能够找到它。
https://stackoverflow.com/questions/11391379
复制相似问题