简体   繁体   English

线程可以安全地创建 FMX.Graphics.TBitmap.Canvas 吗?

[英]Can FMX.Graphics.TBitmap.Canvas safely be created by threads?

I'm maintaining a Delphi 10.2.3 Isapi application that uses FMX.Graphics.TBitmap.我正在维护一个使用 FMX.Graphics.TBitmap 的 Delphi 10.2.3 Isapi 应用程序。 Multiple threads are creating their own private bitmap, draw on it, return the binary content to the webrequest handler, and free the bitmap.多个线程正在创建自己的私有bitmap,在其上绘制,将二进制内容返回到 webrequest 处理程序,并释放 bitmap。 While debugging access violations are occuring in this stack trace:在此堆栈跟踪中发生调试访问冲突时:

:760c4742 KERNELBASE.RaiseException + 0x62
System.DynArraySetLength(nil,$407163,16,$F)
System.DynArraySetLength($6113648,$5DDE84,1,$6B6FE78)
System.Generics.Collections.TListHelper.InternalSetCapacity(8514146)
System.Generics.Collections.TListHelper.InternalGrow(???)
System.Generics.Collections.TListHelper.InternalGrowCheck(???)
System.Generics.Collections.TListHelper.InternalAddManaged((no value))
System.Messaging.TMessageManager.SubscribeToMessage(???,(FMX.Canvas.D2D.TCanvasD2D.ContextLostHandler,$6122F70))
FMX.Canvas.D2D.TCanvasD2D.CreateFromBitmap(???,SystemDefault)
FMX.Graphics.TBitmap.GetCanvas
Unit1.TWorker.Execute

I suspect that this code in the FMX framework code is not threadsafe:我怀疑 FMX 框架代码中的这段代码不是线程安全的:

// FMX.Canvas.D2D.pas:
constructor TCanvasD2D.CreateFromBitmap(const ABitmap: TBitmap; const AQuality: TCanvasQuality);
begin
  inherited;
  FLastBrushTransform := TMatrix.Identity;
  CreateResources;
  FContextLostId := TMessageManager.DefaultManager.SubscribeToMessage(TContextLostMessage, ContextLostHandler);
end;

It is calling the singleton TMessageManager.DefaultManager and adding a handler to it's internal dictionary, without any locking.它正在调用singleton TMessageManager.DefaultManager 并将处理程序添加到它的内部字典中,没有任何锁定。 That doesn't look very threadsafe.这看起来不是很线程安全。 According to the documentation FMX bitmaps can be used in threads when using BeginScene and EndScene, which is fine.根据文档,当使用 BeginScene 和 EndScene 时,可以在线程中使用 FMX 位图,这很好。 But actually creating/destroying a FMX canvas does not seem to be threadsafe because of the subscribe/unsubscribe to the singleton default MessageManager?但实际上创建/销毁 FMX canvas 似乎不是线程安全的,因为订阅/取消订阅 singleton 默认 MessageManager? Is this assumption correct?这个假设正确吗?

The strange thing is that it might only raise access violations when any code has been paused and resumed somewhere in the debugger via a breakpoint.奇怪的是,当任何代码通过断点在调试器中的某个位置暂停和恢复时,它可能只会引发访问冲突。 When the program is never paused by breakpoints it will run without problems.当程序从不被断点暂停时,它将毫无问题地运行。

I confirm you that code in FMX.Graphics.TBitmap.Canvas is not threadsafe.我向您确认 FMX.Graphics.TBitmap.Canvas 中的代码不是线程安全的。 just look at it you will for exemple see that it's listen for message and messaging is not threadsafe只需看看它,您将例如看到它正在侦听消息并且消息传递不是线程安全的

constructor TD2DBitmapHandle.Create(const AWidth, AHeight: Integer; const AAccess: TMapAccess);
begin
  inherited Create;
  FWidth := AWidth;
  FHeight := AHeight;
  FAccess := AAccess;
  FContextLostId := TMessageManager.DefaultManager.SubscribeToMessage(TContextLostMessage, ContextLostHandler);
end;

If you look the code of tcontext3d you will see that it use intensively global variable and thus can not be multi thread.如果您查看 tcontext3d 的代码,您会发现它使用密集的全局变量,因此不能是多线程的。 Tcontext3d is use when you do for example bitmap.canvas.beginscene Tcontext3d 用于例如 bitmap.canvas.beginscene

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM