操作系统: Linux
lib: glibc
我有多个线程访问一个硬件,并且我通过使用互斥来防止争用。
软件非常复杂,其可能的死锁可能存在于系统中,原因是递归调用获取锁。由于这个原因,我使用'pthread_mutex_timedlock‘而不是’pthread_lock‘。我宁愿打印一条错误消息并继续,也不愿导致系统监视并重置。这将允许我在不关闭系统的情况下看到问题。
这里有一些代码片段,可以帮助你理解我想要做的事情。
pthread_mutex_t MainMutex = PTHREAD_MUTEX_INITIALIZER;
#define m_TAKE_LOCK() { \
struct timespec abs_time; \
clock_gettime(CLOCK_REALTIME , &abs_time); \
abs_time.tv_sec += 5; \
if (pthread_mutex_timedlock (&MainMutex, &abs_time) != 0) \
{ \
printf("Lock failed PID %d %s\n", getpid(), __func__); \
} \
}
#define m_RELEASE_LOCK() pthread_mutex_unlock(&MainMutex);
void func1(void) {m_TAKE_LOCK()}
void func2(void) {m_TAKE_LOCK()}
void main(void)
{
while (1)
{
func1();
func2();
m_RELEASE_LOCK()
...
}
}还有其他线程也获得了锁,但这不是问题。我遇到的问题是锁的超时永远不会发生。它永远等待并监视系统,这正是我试图避免的。
'abs_time.tv_sec‘是正确的-我已经打印了它,系统时钟在我尝试使用它的时候已经初始化了。
我知道Windows会阻止对同一进程的锁定,但Linux没有这样的保护。我意识到我不应该递归地调用m_TAKE_LOCK(),但是使用时间锁的目的是捕获but (打印一条消息并继续)。
有人知道我可能做错了什么吗?
发布于 2011-12-17 09:08:14
您不能尝试获取已持有的互斥锁。这是不允许的。你假设它会产生一个特定的结果,并且不能保证它会这样做。
你应该使用递归互斥。你应该释放它的次数与你获得它的次数相同。
但是,从根本上讲,绝对要求任何获取互斥的代码都必须知道,当它运行时,它持有哪些与该函数可能直接或间接调用的代码相关的互斥。(它不需要知道调用它的代码持有的“更高级别”互斥锁,但不需要被它可能调用的函数所触及。)
因此,举个例子,如果你要创建一个调用"Bar“的类"Foo”,那么"Foo“类的每个函数都必须知道它持有的与"Foo”或"Bar“相关的锁。如果某个新类"Qux“调用它,"Foo”代码不需要知道持有什么"Qux“锁,但如果"Qux”在持有"Bar“锁的同时调用"Foo”,"Foo“函数必须知道这一点。您必须实现一个合理的锁层次结构。(除非您完全理解此规则的基本原理,并确定它不适用。)否则,您的代码将永远不会正常工作,除非偶尔走运。
POSIX spec不要求它超时:“如果在不等待另一个线程解锁互斥锁的情况下,互斥锁不能被锁定,那么当指定的超时到期时,等待将被终止。”没有其他线程需要等待。如果: EDEADLK检测到死锁条件或当前线程已经拥有互斥锁,则pthread_mutex_timedlock()函数可能会失败。“可能”表示错误条件,其支持是可选的,术语“在以下情况下应失败”用于表示所需的行为。
发布于 2011-12-17 09:10:54
您的代码在我的linux机器上运行良好:
nils@doofnase:~$ gcc test.c -o test -lpthread -lrt
nils@doofnase:~$ ./test
Lock failed PID 2333 func2
Lock failed PID 2333 func2
Lock failed PID 2333 func2
Lock failed PID 2333 func2
^C这是我所期望的输出。
https://stackoverflow.com/questions/8541818
复制相似问题