RPi2、OpenMAX、死锁

RPi2, OpenMAX, Deadlock

环境

用例

问题描述

第一个端口被启用到相机输入端口(端口#73),该端口正在使用“OMX_CommandPortEnable”命令启用,与“OMX_CommandPortDisable”命令一样,它预计相机组件会触发具有“eEvent == OMX_EventCmdComplete”和“nData1 == OMX_CommandPortEnable”的“OMX_CALLBACKTYPE::EventHandler”事件处理程序,但是,这永远不会发生并且应用程序无限等待端口启用。

问题分析

我将 std::condition_variable 与 std::mutex 结合使用以等待状态更改完成,因此,OMX_CALLBACKTYPE::EventHandler 更新条件变量并调用“notify_one( )”,而调用者线程锁定 std::mutex 并等待设置条件变量,使用这种方法“OMX_CALLBACKTYPE::EventHandler” 永远不会被调用(带有任何参数),程序将永远锁定。
注意:当等待条件变量时,互斥量被验证为不被拥有,这是通过验证(0 == std::mutex::__owner)来完成的。
HOWEVER,通过调用 usleep 和 OMX_GetParameter(OMX_IndexParamPortDefinition) 迭代轮询端口状态时一切正常。

手头的问题

为什么在轮询它的值时触发“OMX_CALLBACKTYPE::EventHandler”,而在使用 conditional_variable 时不触发?在 windows 中有 APC 和可警报线程的概念,在 linux 中是否有任何等价物?一个可以解释上面提到的?

我的经验是,启用端口不会发出事件回调,直到端口填充了缓冲区。即序列为:

  • 将端口设置为启用(OMX_SendCommand()OMX_CommandPortEnable)。
  • 填充端口缓冲区(OMX_AllocateBuffer()OMX_UseBuffer())。
  • 收到OMX_CommandPortEnable事件回调。

如果您在分配缓冲区之前等待事件回调,那么您将遇到死锁。

当您通过测试 OMX_PARAM_PORTDEFINITIONTYPE.bEnabled 进行轮询时,那将立即 return OMX_TRUE 因为 the spec 说这个成员是同步设置的:

The port shall immediately set bEnabled in its port definition structure when the port receives OMX_CommandPortEnable.

以下是我认为当 "work":

时你会发生的情况
  • 将端口设置为启用。
  • 轮询直到 bEnabledOMX_TRUE(立即发生)。
  • 填充端口缓冲区。
  • 收到OMX_CommandPortEnable事件回调。

您可能误以为它是按以下顺序发生的:

  • 将端口设置为启用。
  • 轮询直到 bEnabledOMX_TRUE(立即发生)。
  • 收到OMX_CommandPortEnable事件回调。
  • 填充端口缓冲区。

这使得使用条件变量似乎以某种方式改变了 OpenMAX 行为。实际上 bEnabledOMX_CommandPortEnable 回调并不是真正报告同一件事。我认为在启用端口和分配其缓冲区之间不需要(或不需要)任何同步。