我使用一个库(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 ,并等待其返回(疯狂,但这就像这个,我无法更改)。所以在这里我进入僵局:(
我有什么选择?
queue
代替synchronize
吗?这是不可能的,因为帧仅在renderFrame时间内有效。我也不想花费额外的内存和时间在内存中复制它。fMyWeRTC.doSomeThink
是否在后台线程中(例如TAnonymousThread.execute
)?那也是非常不透明的,文档没有说明我们是否可以从后台线程调用任何函数(当我尝试时,有时会有一些异常)。为了保持安全,我宁愿从主UI线程调用所有内容那么如何处理这种情况?
答案 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;