pthread_mutex_timedlock未超时

pthread_mutex_timedlock未超时,c,linux,embedded-linux,C,Linux,Embedded Linux,操作系统:Linux lib:glibc 我有多个线程访问一个硬件,我通过使用互斥来防止争用 该软件非常复杂,由于递归调用获取锁,系统中可能存在死锁。因此,我使用“pthread\u mutex\u timedlock”而不是“pthread\u mutex\u lock”。我宁愿打印一条错误消息并继续,也不愿让系统监视并重置。这将允许我在不破坏系统的情况下看到问题 下面是一段代码,可以帮助您理解我要做的事情 pthread_mutex_t MainMutex = PTHREAD_MUTEX_I

操作系统:Linux

lib:glibc

我有多个线程访问一个硬件,我通过使用互斥来防止争用

该软件非常复杂,由于递归调用获取锁,系统中可能存在死锁。因此,我使用“pthread\u mutex\u timedlock”而不是“pthread\u mutex\u 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(),但使用timedlock的目的是捕获bug(打印消息并继续)


有人知道我可能做错了什么吗?

您不能尝试获取已持有的互斥锁。这是不允许的。您假设它将产生特定的结果,但不能保证它会这样做

您应该使用递归互斥。你应该释放它的次数与你获得它的次数相同

然而,从根本上说,任何获取互斥体的代码都必须知道,在运行时,它所持有的互斥体与函数可能直接或间接调用的代码相关,这是一个绝对的要求。(它不需要知道调用它的代码所持有的“更高级别”互斥体,但它可能调用的函数不会触及这些互斥体。)

因此,例如,如果要创建一个名为“Foo”的类来调用“Bar”,那么“Foo”类的每个函数都必须知道它所持有的与“Foo”或“Bar”关联的锁。如果某个新类“Qux”调用它,“Foo”代码不需要知道持有什么“Qux”锁,但是如果“Qux”在持有“Bar”上的锁时调用“Foo”,则“Foo”函数必须知道这一点。必须实现sane锁层次结构。(除非您完全理解此规则的基本原理并确信它不适用。)否则,除非偶尔运气好,否则您的代码永远不会正常工作

不要求它超时:“如果在不等待另一个线程解锁互斥锁的情况下无法锁定互斥锁,则在指定的超时过期时,此等待将终止。”没有其他线程可等待。它也不需要错误,“pthread_mutex_timedlock()函数可能会在以下情况下失败:
[EDEADLK]检测到死锁情况或当前线程已拥有互斥锁。“可能”表示错误情况,其支持是可选的,术语“如果”用于表示所需的行为。

您的代码在我的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

这是我所期望的输出。

如果使用
pthread\u mutextatr\u settype(3posix)
将互斥设置为type
pthread\u mutex\u RECURSIVE
,您应该能够在单个线程内递归地获取锁。样式问题:您应该使用
do{…}while(0)
而不是
{…}
,因为它允许附加一个
到它的调用,这要好得多。并将其用于拍摄和发布。感谢您的理智检查。有时我对嵌入式系统如此着迷,以至于忘了我可以在我的Linux机器上检查它。这就是违反规则的代码的本质——有时它做你期望的事情,有时它不做。然而,在我看来,你的期望是错误的。POSIX说。这里没有其他线程可以等待。不需要EDEADLCK检测,这是一个“可能”。感谢您花时间回答此问题。您对posix规范的引用很清楚,但我忽略了它。我将研究递归锁。这似乎更适合我的需要,以防止在对互斥锁进行意外递归调用时系统挂起。