关于TThread.synchronize的死锁

时间:2018-12-18 07:42:26

标签: delphi

我使用一个库(WebRTC),该库在其自己的不透明背景线程之一中触发所有事件。这就是我要面对的流程:

:: MainUIThread
fMyWeRTC.doSomeThink;

:: WebRTC own and opaque background Thread
Procedure fMyWebRTC.renderFrame(frame: TRTCFrame);
begin
  TThread.synchronize(nil,
  procedure 
  begin
    ... Draw the frame .... // I can render only in main UI thread
  end;
end;

问题在于,当您调用fMyWeRTC.doSomeThink;时,库在其自己的后台线程中内部调用renderFrame ,并等待其返回(疯狂,但这就像这个,我无法更改)。所以在这里我进入僵局:(

我有什么选择?

  1. 使用queue代替synchronize吗?这是不可能的,因为帧仅在renderFrame时间内有效。我也不想花费额外的内存和时间在内存中复制它。
  2. fMyWeRTC.doSomeThink是否在后台线程中(例如TAnonymousThread.execute)?那也是非常不透明的,文档没有说明我们是否可以从后台线程调用任何函数(当我尝试时,有时会有一些异常)。为了保持安全,我宁愿从主UI线程调用所有内容

那么如何处理这种情况?

1 个答案:

答案 0 :(得分:0)

一种避免死锁的简单方法是完全避免Synchronize。我们不知道为什么为什么使您无法显示代码,但是一种选择可能是将Queue与您自己的同步一起使用,即:

Procedure fMyWebRTC.renderFrame(frame: TRTCFrame);
const
  RENDER_TIMEOUT = 1500;  { ms }
var
  LEvent : TEvent;
begin
  LEvent := TEvent.Create;      
  try
    LEvent.ResetEvent;
    TThread.Queue(nil,
      procedure 
      begin
        try
          // Draw Frame
        finally
          LEvent.SetEvent;
        end;
      end);
    LEvent.WaitFor(RENDER_TIMEOUT);
    { can check return value here and branch on failed wait, etc... 
      Be careful that LEvent may be freed below on a failed wait
      before it is used in the queued work above.  Need to handle
      that case yourself.
    }
  finally
    LEvent.Free;
  end;
end;