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 有严格的线程规则。我猜GdiplusStartupGdiplusShutdown 在调用线程上初始化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+ 和多线程的主要内容,如果未能解决你的问题,请参考以下文章

GDI+ 多线程绘图

多线程和多进程的区别

多线程和多进程模式有啥区别

python 多进程和多线程配合

python多线程和多线程问题

多进程和多线程有啥区别?