GDI+ 和多线程
Posted
技术标签:
【中文标题】GDI+ 和多线程【英文标题】:GDI+ and Multi-Threading 【发布时间】:2020-02-03 13:57:03 【问题描述】:根据我找到的所有信息,GDI+ 能够以多线程方式使用,只是限制不能从多个线程同时使用 GDI+ 对象。
我的 C++ MFC Windows 应用程序中有两个线程偶尔崩溃的问题(一个在启动时关心启动窗口,另一个是主线程做一些初始化工作)。崩溃是不可重现的,但有一个共同点:当程序在调试器中停止时,这两个线程中至少有一个线程处于 GDI+ 操作中。
这里有人了解 GDI+ 线程吗?
【问题讨论】:
据我所知,GDI+ 在内部使用 Windows 映像组件。 WIC 基于 COM。 COM 有严格的线程规则。我猜GdiplusStartup
和GdiplusShutdown
在调用线程上初始化COM。如果我的猜测是准确的,你不能在任意线程上调用 GDI+ 函数。
原来,我猜错了。在GdiplusStartup
中没有对CoInitialize[Ex]
的呼叫。尽管如此,GDI+ 对象经常拥有 GDI 对象。如果这恰好是一个设备上下文,您订阅subtle thread affinity rules。
据我了解,GdiPlusStartup 将为所有线程调用一次。而且我绝对不会从两个线程访问任何 DC 或 GDI+ 对象(因为它们都关联到不同的窗口)。
【参考方案1】:
最好使用“双缓冲”机制,为每个map创建2个memory DCs,一个一个使用。也就是说,主窗口读取内存DC A进行显示,而后台线程在内存DC B上绘制,绘制完成后通知主线程。通知主线程后,交换A和B(显示B,A是下一个后台线程操作的对象)。
关于GdiplusStartup:
您可以在一个线程上调用 GdiplusStartup 并在一个线程上调用 GdiplusShutdown 另一个线程,只要您删除所有 GDI+ 对象(或 在调用 GdiplusShutdown 之前,它们会超出范围。
该文档还包括其他一些用法。 它还提到了如何在 GDI+ 中使用动态数据交换 (DDE):
如果您想为您的应用程序初始化 GDI+(通过调用 GdiplusStartup 在你的 InitInstance 函数中),你必须抑制 GDI+ 后台线程。
【讨论】:
GDI 对象与 GDI+ 不同。 是的,谢谢指出,我还是推荐OP使用“双缓冲”。 这是指多线程 GDI 绘图。我认为 GDI 的多线程功能非常清楚(只要我使用一个 DC 或一个 GDI 对象只从一个线程中,它就可以工作),但我的问题仍然是关于 GDI+ 的问题。 @DrakeWu-MSFT:我为什么要抑制 GDI+ 后台线程? @nic:这仅适用于同时使用CWinApp
和DDE(记录在here)的情况。 If you suppress GDI+ background thread, then you are expected to pump messages yourself 详细介绍了您的责任,如果您决定取消 GDI+ 的后台线程。以上是关于GDI+ 和多线程的主要内容,如果未能解决你的问题,请参考以下文章