线程与VCL的消息同步

http://www.zzyubo.com/runsoft/article.asp?id=34

Delphi实现多线程很简单,得益于TThread的良好封装。若在线程中使用VCL,例如要宣告一个事件,并在线程中触发它,一般的方法是使用Synchronize。
在Project中这么用可能没什么,但在Dll中呢?例如在链接库中封有窗口,并在里面实现一个与滚动条界面打交道的线程。
当 线程用Synchronize同步时,会被锁死,由此产生另外一种特效:移动鼠标,线程操作的滚动条就改变进度;否则进度条就不见动静。事实是线程被锁死 了,准确的说是Synchronize中WaitForSingleObject函数无法返回,它在等主进程处理完进度条后返回,但主进程似乎没有搭理 它。

而且Synchronize还有一个缺点,就是除了要同步的过程外,无法传递其他参数。
消息机制的同步,大体分三个部分:
1.发送(由线程完成)
2.接收(由主进程完成)
3.处理(由主进程完成)

可以看到,线程只要发送需要同步的数据(事件)就可以了,其它都是在主进程里完成的。
实现:
1.TZipThread = class(TThread)
protected
procedure DoProcessBar; //负责发送进度条数据
end;

2.TThreadEvent = class
protected
FHwnd: THandle; //消息句柄
procedure DoProcessBar(nValue: Cardinal); //负责接收数据
procedure WndProc(var nMsg: TMessage); //负责处理数据
end;

大致的框架就是这样,现在让它运行起来:
1.
TZipThread.DoProcessBar; //发送
begin
Event.DoProcessBar(55);
end;

2.
TThreadEvent.DoProcessBar; //接收
begin
FBarValue := nValue;
PostMessage(FHwnd, WM_MyData, 0, 0);
end;

3.
TThreadEvent.WndProc(var nMsg: TMessage); //处理
begin
if nMsg.Msg = WM_MyDATA then ProcessBar1.Position := FBarValue;
end;

很简单吧,说白了就是在线程中维护一个消息队列,需要与VCL打交道时就发消息,至于VCL是否处理或是否处理完毕,那是别人的事,咱作线程的不管这个。

那么,由此产生了两个问题:1.VCL处理的肯定没有线程快,那么后来的数据会覆盖先来的。2.对进度条而言,进度刚显示完10就一下子跳到100了。
解决方法是:1.对于只触发一次的事件,使用变量缓存;对于多次触发的,使用TThreadList缓存成列表,然后在处理时依次对List操作。2.没办法解决。因为线程发出消息后不管,VCL处理总会滞后。

posted on 2011-05-05 16:36  chulia  阅读(276)  评论(0编辑  收藏  举报

导航