3

这是在 Linux 上,但理想情况下我想要一个符合 POSIX 的解决方案。

我有两个线程,每个线程都能够通过 API 函数写入硬件总线。在任何给定时间只允许一个线程写入总线,并且在总线写入之后,在几百毫秒数量级的给定时间内不得写入总线。

两个线程都实现为状态机。

显而易见的解决方案是使用互斥锁来串行访问总线,设置计数器或时间戳,并在适当的时间到期后让状态机解锁互斥锁。

这对我来说似乎有点脆弱。如果未来的维护开发人员错误地修改了状态机,互斥锁可能不会被释放,从而导致难以诊断的死锁。

是否有一个 API 调用可以锁定互斥体,但在给定超时后自动解锁它?Google 揭示了 pthread_mutex_timedlock(),但这并不完全相同。

4

3 回答 3

3

我不知道任何允许自动释放锁的 pthreads API。

就个人而言,我会尝试通过单个线程序列化对总线的访问,以避免这些并发症。如果该线程维护一个输入队列并且其他线程将它们的请求发布到它,那么它可以执行它希望的任何序列化和冲突解决,这也使得在进一步访问之前实现延迟变得更容易。只要您小心不要在此线程中使用任何阻塞函数,您唯一真正的失败情况就是它可能会意外终止。

如果您需要从总线读取和写入,您可以给每个线程一个输入队列,并让工作线程向 IO 线程发布一个“读取请求”,然后等待响应被发送回它自己的输入队列。如果一个线程只有一个未完成的请求,那么你真的不需要队列,一个简单的条件变量和一个指向要填充的结构的指针可能工作得很好。

如果您确实希望两个线程共享资源,那么我认为您总是会有互斥锁被锁定的风险。即使您设置了一个计时器并在固定时间后强制释放互斥锁,这也可能会导致不同的错误,即一个线程继续使用资源,认为它拥有锁,而实际上它完全由另一个线程持有。最终,您正在尝试针对未来的编程错误计划稳健性,这是一个很好的目标,但有一个限制 - 互斥锁只是一个必须小心的东西。

如果您必须使用互斥锁,我建议您最好的方法是简单地最小化需要互斥锁的代码并避免阻塞其中的调用。如果您正在实现状态机,请尝试确保互斥锁不必在状态转换之间保持锁定状态。如果可能的话,确定您的互斥锁的范围,以便它们仅在调用链中某个级别的单个函数调用期间保持 - 这使得通过肉眼发现锁定/解锁不匹配变得容易得多。如果您使用的是 C++,那么使用RAII使您的锁释放更加可靠。

但是再一次,我认为您会发现以某种方式序列化您的请求会容易得多,通常是通过将一个线程声明为仲裁器(现有线程之一或新线程之一)。

于 2013-01-18T11:54:44.663 回答
1

如果遇到这个问题,我可能会使用另一个“APIwrite”线程与驱动程序交互。该线程将围绕生产者-消费者队列弹出和睡眠(数百毫秒)循环。任何其他希望写入的线程只需将 *writeBuffer 排队。writeBuffer 结构可以包含一个函数(*writeBuffer) 指针,APIwrite 线程将在写入后调用该指针。该函数由原始线程提供,可以
发出原始线程正在等待的某个事件的信号,也可以只释放 *writeBuffer。

避免使用显式互斥锁、计时器等,并允许同步或异步写入。

于 2013-01-18T12:12:28.683 回答
1

在共享(和互斥体覆盖的)内存中拥有最后一次总线访问的时间戳怎么样?每次写入都将如下所示:

  1. 锁定互斥锁
  2. 检查上次访问的时间戳;如果您的等待时间尚未过去,请在这段时间的剩余时间里休眠,因为无论如何您都无法在此线程中执行任何其他操作
  3. 更新上次访问的时间戳
  4. 解锁互斥锁
于 2013-01-18T11:59:39.463 回答