VCL。
要记住Execute() 需要经常地检查Te rminated属性的值,来确认是否要提前退出。尽管这将意味着
当使用线程工作时,你必须关心更多的事情,但它能确保在线程结束时,能够完成必要的清除。下面
是一段在E
x
ecute()增加处理操作的简单代码:
注意某些紧急情况下,你可以使用Win32 API函数Te rminateThread()来终止一个线程。但是,除非没有别的办法了,否则不要用它。例如,当线程代码陷入死循环时。Te rminateThread()的声明如下:
function Te rminateThread(hThread:THandle;dwExitCode:DWORD);
T Thread的H andle属性可以作为第一个参数,因此,Te rminateThread()常这样调用:
Te rminateThread(MyHosedThread.Handle,0)
如果选择使用这个函数,应该考虑到它的负面影响。首先,此函数在Windows NT与在Windows 95/98下并不相同。在Windows 95/98 下,这个函数能够自动清除线程所占用的栈;而在Windows NT下,在进程被终止前栈仍然保留。其次,无论线程代码中是否有t ry. ..finally块,这个函数都会使线程立即停止执行。这意味着,被线程打开的文件没有被关闭、由线程申请的内存没有被释放等情况。而且,这个函数在终止线程的时候也不通知D LL,当D LL关闭时,这也容易出现问题。在第9章“动态链接库”中有关于这方面的更多内容。11.2.4 与VCL同步
如同在前面多次提到的,对V CL的访问只能在主线程中。这将意味着:所有需要与用户打交道的代码都只能在主线程的环境中执行。这是其结构上明显的不足,并且这种需求看起来只局限在表面上,但它实际上有一些优点。
1. 单线程用户界面的好处
首先,只有一个线程能够访问用户界面,这减少了编程的复杂性。Wi n32要求每个创建窗口的线程都要使用G etMessage()建立自己的消息循环。正如你所想的,这样的程序将会非常难于调试,因为消息的来源实在太多了。
其次,由于V CL只用一个线程来访问它,那些用于把线程同步的代码就可以省略了,从而改善了应用程序的性能。
2. Synchronize()方法
在T T h r e a d中有一个方法叫S y n c h r o n i z e ( ),通过它可以让线程的一些方法在主线程中执行。S ynchronize()的声明如下:
参数
M e
th
od的类型是T ThreadMethod类型(这是一个无参数的过程),类型声明如下:
M ethod参数用来传递要在主线程中执行的方法。以T Te stThread显示计算的结果。首先要在T Te stThread中增加能对编辑控件的Te xt属性进行修改的方法,然后,用S ynchronize()来调用此方法。
我们给这个方法取名为G iveAnswer()。在清单11 -1中列出了例子的代码,其中包含了更新主窗体的编辑控件的代码。
清单11-1 ThrdU.PA S单元
你已经知道S ynchronize()的作用是在主线程中执行一个方法。但是,你或许已把S ynchronize()当成一个黑匣子,不清楚它是如何工作的。如果愿意揭开这个谜,请继续向下读。
当你在程序中第一次创建一个附属线程时,V CL将会从主线程环境中创建和维护一个隐含的线程
窗口。此窗口唯一的目的是把通过S ynchronize()调用的方法排队。
S ynchronize()把由M ethod参数传递过来的方法保存在T Thread的F Method字段中,然后,给线程窗口发一个C M_EXECPROC消息,并且把消息的l Param参数设为s elf(这里指线程对象)。当线程窗口的窗口过程收到这个消息后,它就调用F Method字段所指定的方法。由于线程窗口是在主线程内创建的,线程窗口的窗口过程也将被主线程执行。因此,F Method字段所指定的方法就在主线程内执行。
图11 -2
形象地说明了
S y
n
c
hr
onize()的内部机制。
辅助线程
Synchronize(Foo):
主线程
隐藏“线程窗口”
线程窗口的窗口过程处理消息。I Param被强制转换为T Thread,并调用FMethod。
设置FMethod为Foo。发送CM_EXECPROC消息到线程窗口,