您的位置:首页 > 移动开发 > Objective-C

多线程绘图之:Multiple Threads and GDI Objects

2010-04-10 10:17 330 查看
我们有可能需要利用多线程来实现并行绘图。

但是,这里面经常会有这样一个问题:多个线程都需要使用同一个GDI对象进行绘制。

进而引申出来的问题是:多个不同的线程能否同时操作同一个GDI对象?

首先看MSDN里官方的document 描述(在MSDN里搜索“Multiple Threads and GDI Objects”):

To enhance performance, access to graphics device interface (GDI) objects
(such as palettes, device contexts, regions, and the like) is not serialized.
This creates a potential danger for processes that have multiple threads sharing
these objects
. For example, if one thread deletes a GDI object while another
thread is using it, the results are unpredictable. This danger can be avoided
simply by not sharing GDI objects. If sharing is unavoidable (or desirable), the
application must provide its own mechanisms for synchronizing access. For more
information about synchronizing access, see Synchronizing Execution
of Multiple Threads.

可见,Windows为了GDI操作的效率,GDI API在设计的时候,没有被设计成线程安全的。

因此不要在多个线程里同时操作同一个GDI对象,如果你必须这么做,那得用同步机制来保证线程对这个GDI对象的依次访问操作。

举个例子:窗口上有2副图件(比如GIS领域里的等值线图,光照晕渲图),这2个图件的绘制过程比较复杂,在后台创建2个worker线程负责绘制。这里的问题是,2个worker线程都需要往同一个窗口上绘制,也就是往同一个DC(device context)上绘制。

DC也是Windows里的GDI对象之一。因此,不能让这2个线程同时调用GDI API对这个DC进行操作(比如:设置笔、文本等)。

对于这个例子中的解决方案: 利用内存DC。让后台work而线程先分配各自的内存DC,所有的绘制操作都在内存DC上进行,完成之后,通知主线程(可以使用PostThreadMessage,异步发送一个用户自定义的消息,[注:不要使用SendMessage函数。有关于消息发送,值得看一下这个文章http://www.flounder.com/messages.htm]),将内存DC上的内容拷贝到(BitBlt)主窗口的DC上。

注意:具体实现时,根据设计,最好利用“双缓冲”机制,针对每一副图件,创建2个内存DC,一前一后使用。也就是主窗口在显示的时候读取内存DC A进行显示;而后台线程在内存DC B上绘制,绘制完成后通知主线程。主线程得到通知后,对A和B进行交换(显示B,而A作为下一次后台线程操作的对象)。

VC Sample里有个例子叫MTGDI,这个例子使用了CRITICAL_SECTION来对“往同一个DC上的绘制操作”进行同步。

在实际应用中,这个方案的效率不好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: