关于使用TThread.synchronize进行死锁 [英] About deadlock with TThread.synchronize

查看:49
本文介绍了关于使用TThread.synchronize进行死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I use a library (WebRTC), that fire all event in one of its own and opaque background thread. So this is the flow I m facing :

:: 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 ,并等待其返回(疯狂,但它是这样制作的,我无法更改).所以在这里我进入了僵局:(

The problem is that when you call fMyWeRTC.doSomeThink;, the library internally call renderFrame in it's own background thread and wait its return (crazy but it's made like this, I can't change it). So here I enter in a deadlock :(

我有什么选择?

  1. 使用 queue 而不是 synchronize ?这是不可能的,因为帧仅在renderFrame的时间内有效.我也不想花费额外的内存和时间在内存中复制它.
  2. fMyWeRTC.doSomeThink 是否在后台线程中(例如,带有 TAnonymousThread.execute )?那也是非常不透明的,文档没有说明我们是否可以从后台线程调用任何函数(当我尝试时,有时会有一些异常).为了保持安全,我更喜欢从主UI线程调用所有内容
  1. Use queue instead of synchronize? no possible because frame is alive only for the time of renderFrame. I don't also want to spend extra memory and time to duplicate it in memory.
  2. Do fMyWeRTC.doSomeThink in a background thread (with for example TAnonymousThread.execute)? that is quite opaque too, the doc doesn't say if we can call any functions from a background thread (when I tried, I have sometimes some exception). To stay on the safe way I prefer to call everything from the main UI thread

那么如何处理这种情况?

So how you can handle this situation?

推荐答案

一种避免死锁的简单方法是完全避免 Synchronize .我们不知道为什么为什么在显示的代码中陷入僵局,但一种选择可能是使用 Queue 进行自己的同步,即:

One simple way to get around the deadlock is to avoid Synchronize altogether. We can't know why you are deadlocking from the code you've shown, but an option might be to use Queue with your own synchronization, ie:

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;

这篇关于关于使用TThread.synchronize进行死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆