pthread_mutex_timedlock没有超时

时间:2011-12-17 00:52:33

标签: c linux embedded-linux

操作系统:Linux

lib:glibc

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

该软件非常复杂,由于递归调用锁定,可能会在系统中出现死锁。出于这个原因,我使用'pthread_mutex_timedlock'而不是'pthread_mutex_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的目的是捕获错误(打印消息并继续)。

任何人都知道我可能做错了吗?

2 个答案:

答案 0 :(得分:4)

您无法尝试获取已经拥有的互斥锁。这是不允许的。您假设它将产生特定结果,并且无法保证它会这样做。

您应该使用递归互斥锁。并且你应该释放它的次数相同。

但是,从根本上说,绝对要求获取互斥锁的任何代码肯定知道它在运行时保留的互斥量与函数可能直接或间接调用的代码有关。 (它不需要知道调用它的代码所拥有的'更高级'的互斥锁,但是它可以调用的函数不会触及它。)

因此,例如,如果你创建一个名为“Foo”的类调用“Bar”,那么“Foo”类的每个函数都必须知道它所拥有的与“Foo”或“Bar”相关的任何锁定。 ”。如果某个新类“Qux”调用它,那么“Foo”代码不需要知道什么是“Qux”锁定,但是如果“Qux”在对“Bar”进行锁定时调用“Foo”,则“Foo”函数必须知道这一点。您必须实现一个理智的锁定层次结构。 (除非你完全理解这条规则的基本原理并且确定它不适用。)否则,你的代码将永远无法正常工作,除非偶尔运气。

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

答案 1 :(得分:1)

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

这是我期望的输出。