在上一篇文章中,我们简单地介绍了控制窗口句柄的线程亲缘性规则。
今天,我们来讲讲设备上下文(Device Context, 简称 DC) 。
设备上下文也有一定程度的线程亲缘性。调用 DC 相关函数,例如 GetDC 的线程,必须在同一个线程中调用其对应的 ReleaseDC。但和窗口句柄一样,在 DC 对象的生存期内,任何线程都可以访问它。
如果你希望以多线程方式使用 DC,则负责协调该设备上下文的使用者,以便一次只有一个线程使用它。
例如,若要跨多个线程承载无窗口控件,主机在主线程上获取 DC,然后按顺序要求每个控件将自身绘制到该 DC 中。一次只有一个控件绘制到 DC 中,即使该控件恰好位于不同的线程上也是如此。
DC 的线程亲缘性比窗口句柄的线程亲缘性要微妙得多,因为如果你搞砸并从错误的线程释放 DC,事情似乎仍然运行良好,但窗口管理器的内部资源记录表会一团糟,你可能会在稍后从 GetDC 获得一个无效的 DC 句柄,然后用户界面会呈现出你所不希望看到的样子,甚至会以应用程序的直接崩溃作为结局。
在下一篇文章中,我将介绍其他的用户界面元素的线程亲缘性,请拭目以待。
总结
复杂用户界面开发起来需要花费一些功夫,在开发拓扑梅尔智慧办公平台(Topomel Box)的过程中,我总是遵循一个简单的原则:仅在主界面线程中操控用户界面对象,工作线程只用来干“脏活累活”。
有了这个统一的规则,你会形成肌肉记忆:这个更新界面的代码应该放在哪里。
简单,是一种美。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Thread affinity of user interface objects, part 2: Device contexts》