比如删除 A) 。 发生的现象:程序死掉。
2) 使用同一资源未加保护引起问题。 A 和 B 同时去对窗体上进行绘图操作,界面可能花掉,也可能黑掉。
出现的现象:界面不再刷新,变成黑色。(最好不要在子线程中去更新界面 UI,可以使用消息来更新)
3) 线程锁使用不当造成死锁。 线程 A 利用线程锁锁住资源 A 后, 再去试图访问资源 B, 线程 B 利用线程锁锁住资源 B
后试图去访问 资源 A。这样就发生了线程互锁。
程序结果:线程死掉。
4) 未加线程保护产生异常。 线程 A 获取到了对象 X (步骤 1)的引用后被挂起(步骤 2),而接下来线程 B 却删除了 X (步骤 3), 线程 A 再次唤醒后访问对象 X 出错(步骤 4)。这个问题是多线程中最容易被忽略的地方,也是异常最可 能发生的情况。
程序结果:线程异常。
5) 消息在线程同步中的问题。 先说说消息的一些基本问题(有关消息的处理部分在 Windows 2000 源码 private\ntos\w32\ntuser\kernel\input.c 文件中): 消息队列的建立: 消息队列的建立:线程在刚建立的时候,是没有消息队列的。当有界面 UI 操作函数被调用的时候(比 如 CreateWindow),Windows 就会为该程序建立一个消息队列,同样,通过调用 PeekMessage/GetMessage 可以强制操作系统为线程建立一个消息队列(参看 MSDN 关于 PostThreadMessage 的说明)。 消息的正常处理流程: 消息的正常处理流程:线程通过 GetMessage/PostMessage 获取消息,然后通过 TranslateMessage 进行字符转换,接下来,通过 User32.dll 模块的帮助最后调用到相应窗口的窗口过程(RegisterClass 时传 入的窗口过程)。 消息重入
问题: 消息重入问题:所谓的消息重入,就是在消息处理过程中再调用 SendMessage 发送消息给目标窗口。 如果控制不好, 就会引发异常。 一个简单的例子: WM_PAINT 中再去 SendMessage(hWin, WM_PAINT, 在 0, 0)。其结果就是堆栈溢出异常了(stack overflow)。(相当于 WndProc 在进行无限递归),
Delphi 代码 如下(可以自己感受一下“Stack Overflow”是怎么一回事,等异常后调出 CallStack 看看^_^): procedure OnPaint(var tMsg: TMessage); message WM_PAINT; // Interface
// Implementation procedure TForm1.OnPaint(var tMsg: TMessage); begin SendMessage(Self.Handle, WM_PAINT, 0, 0); end; SendMessage &; PostMessage: SendMessage 发送一个消息给窗口,同时,操作系统会去直接调用 窗口的窗口过程而不经过线程的消息队列。 PostMessage 则仅仅是将消息投递到消息队列, 而 应用程序通 过 GetMessage/PeekMessage 获取消息处理后再交给系统分发消息。
消息在多线程中的问题: 消息在多线程中的问题: 分析一个具体过程说明在多线程中因消息而引起的问题: 线程 A (主线程) 通过 GetMessage->DispatchMessage, 接下来通过 User32 模块的帮助调用 WndProc 进行消息处理的过程对 RichEdit 中插入一张图片。其步骤如下: 1. 在 RichEdit 中定位要插入的位置(X, Y)。RichEdit->SetSel(X, Y) 2. 创建 OLE 对象。 3. 获取 ClientSite 接口插入对象。
线程 B 通过 SendMessage 调用 WndProc 要求在 RichEdit 的末尾添加一段文字。其步骤如下: 1. 定位到 RichEdit 末尾。
RichEdit->SetSel(-1, -1); 2. 调用 RichEdit->ReplaceSel(sText)插入文本。
假如线程 A 在步骤 1 刚运行完毕后,其运行时间片结束,线程被挂起,当前的状态被保存到线程 A 的 堆栈中。线程 B 开始运行,线程 B 插入文本完成返回,线程 A 重新被唤醒,开始执行步骤 2,3, 而这时, 线程 B 已经改变了当前的插入位置,线程 A 并不知道,于是,就会出现插入的图片错位现象。 归根结底,是线程的同步问题。 结论: 结论:尽量用 PostMessage 而不是 SendMessage。 6) 异常引起的问题。 看这段代码: CCriticalSection m_cLock;
m_cLock.