线程与GDI的冲突:死机的主要原因---如何理解?
梁肇新《编程高手箴言》94页内容:
很多人在使用线程的时候,都喜欢在线程内画图,程序就会很容易出错,而且还是那种没有任何响应和提示的错误问题。
例如,如下是一个文件复制的程序,这个程序由两个线程组成,一个是复制文件的线程,另一个是显示文件复制进度的过程。当文件复制一部分后,进度条就向前移动一点。理论上,这个程序没有什么问题。但是,这个程序有一个很大的隐患,即主程序也可能某一时刻要更新这个进度条。例如,进度被其他窗口挡住后或者整个窗口放大缩小时,整个窗口就要刷新,这时,线程的那个部分也要刷新它,操作系统也要刷新它。这样,三个部分都要去刷新它,程序就很容易死锁。
这时会什么响应也没有了。这种问题在多线程中是很常见的。那怎么处理这个问题呢?
有一条原则,即程序中的线程一概不直接操作线程部分中的GDI。它只要发一个消息给主程序,让主程序来绘制图形,就不会出现任何的问题。
发送消息的方法就是用PostMessage。但一定不能用SendMessage。因为用PostMessage可以让主程序去调度绘图,而SendMessage会立即去绘制图形。
上面所说不是太明白。
是不是包含这种情况:在一个线程内,调用某个窗口的Invalidate,然后再调用UpdateWindow,那么这样做是有隐患的,因为UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重绘。这个重绘可能与系统正在进行的重绘发生冲突,导致死锁。如果没有使用UpdateWindow,那么就是安全的。因为在Invalidate后,在WM_PAINT消息被处理后,系统会调用OnPaint进行窗口刷新,系统会协调这个刷新和系统正在进行的刷新,因此是安全的。
因为我现在的一个程序有问题,一直不能解决,怀疑和这个方面有关。
还请高手们解惑。多谢。
[解决办法]
三个部分都要去刷新它不会发生死锁,windows会把这些WM_PAINT合成为一个WM_PAINT然后发送给对应线程
[解决办法]
我越看越觉得他讲的没道理,你最好看一下msdn然后自己试一下
[解决办法]
出什么错误了?GDI最后也得走UI线程啊。
[解决办法]
这个UpdateWindow引起的OnPaint是等系统将正在执行的OnPaint执行完再执行
“不顾一切”地执行自己的OnPaint,即与系统正在执行的OnPaint并行执行,这完全不可能
[解决办法]
被send的message不是被立即执行,要等到GetMessage或PeekMessage开始处理非队列消息
[解决办法]
如果调用UpdateWindow,那么WM_PAINT的处理是不标准的,不规则的,其可靠性是不能保证的,可能造成线程的死锁。直接的原因是多个OnPaint被并行执行,并且OnPaint由于内部的原因,例如不可重入,导致出现问题。
这个不对,如果需要重绘,UpdateWindow等到WM_PAINT被处理完再返回,InvalidateRect把矩形设为无效然后返回,系统在合适的时候发送WM_PAINT
如果调用UpdateWindow,那么WM_PAINT的处理是标准的,也是规则的,其可靠性是可以保证的,不太可能成线程的死锁。多个OnPaint被不会并行执行,因为一个线程不可能同时执行多个程序。
[解决办法]
标准做法还是发送自消息到窗口那里让其绘图
[解决办法]
如果调用UpdateWindow,那么WM_PAINT的处理是不标准的,不规则的,其可靠性是不能保证的,可能造成线程的死锁。直接的原因是多个OnPaint被并行执行,并且OnPaint由于内部的原因,例如不可重入,导致出现问题。
============
不可能的,不可能有多个OnPaint并行执行的。
[解决办法]
类似的问题我遇到过
问题不在于绘制本身
而在于绘制时对相关数据处理
但就WM_PAINT消息肯定是要在消息队列里等待的
可是如果在发送这个消息之前主线程和辅助线程都在处理绘制数据而此时没有互斥控制就容易出问题
[解决办法]