邪恶八进制信息安全团队技术讨论组's Archiver

haicao 2005-2-3 00:12

[转载]线程

(I)线程的中止
   看了几本书,提到线程的中止主要有三种途径:线程所属进程中止;线程内部调用EndThread函数;线程外部调用TerminateThread函数。
  1. 线程所属进程中止这一条似乎可有可无?(问题一)事实上每次应用程序关闭之前都还要检查是否还有未结束的线程,如果还有线程没结束比如正在进行数据库等操作,则关闭应用程序可能会出问题:( 对于这个问题,一直搞不清楚,有没有必要在应用程序结束前检查并结束所有线程?(问题二)
   2.EndThread函数 当线程函数Excute()执行完毕,它会调用Delphi的标准例程EndThread,这个例程再调用A P I函数E x i t T h r e a d ( )。由ExitThread() 来清除线程所占用的栈。按照这种说法,我们在线程函数中直接调用EndThread(0)应该可以直接结束线程执行,并且释放了线程所占用的资源?(问题三:是这样的吧,我还没来得及试)这样就可以结合线程的Terminated属性,有如下代码了:
在线程函数中频繁检查Terminated属性
if(self.Terminated or Application.Terminated) EndThread(0)
   3.TerminateThread函数是Win32API函数,其声明如下:function Te r m i n a t e T h r e a d ( h T h r e a d : T H a n d l e ; d w E x i t C o d e : D W O R D ) ;  T T h r e a d的H a n d l e属性可以作为第一个参数,因此,Te r m i n a t e T h r e a d ( )常这样调用:
Te r m i n a t e T h r e a d ( M y H o s e d T h r e a d . H a n d l e , 0 )如果选择使用这个函数,应该考虑到它的负面影响。首先,此函数在Windows NT与在Windows 95/98下并不相同。在Windows 95/98 下,这个函数能够自动清除线程所占用的栈;而在Windows NT下,在进程被终止前栈仍然保留。其次,无论线程代码中是否有t r y. . . f i n a l l y块,这个函数都会使线程立即停止执行。这意味着,被线程打开的文件没有被关闭、由线程申请的内存没有被释放等情况。而且,这个函数在终止线程的时候也不通知D L L,当D L L关闭时,这也容易出现问题(摘自Steve Teixeira和Xavier Pacheco的Delphi5开发人员指南,问题四:不知道这种情况对于win2000是否适用?)
   4.关于waitfor方法 等待线程结束可以调用它的WaitFor方法。不过有些不解之处。比如Delphi5开发人员指南中有这样一段代码:
for i:=ThreadList.count-1 downto 0 do begin
  TDrawThread(ThreadList[i]).Terminate;
  TDrawThread(ThreadList[i]).waitfor;
  //(问题五:如果线程设置了FreeOnTerminate:=true,则调用Terminate之后,有没有可能线程马上被终止且释放了资源,此时若调用waitfor会不会出问题?)
end;

  综上,如果结束一个线程比较稳妥的方式是这样:首先,在线程函数中频繁检查Terminated属性,发现为True时,调用EndThread(0)方法结束线程;在需要的时候调用线程的Terminate方法将线程的Terminated属性设置为true即可达到结束线程的问题;为了确保线程已经终止,使用waitfor方法进行确认。

II 线程的同步
  1.临界区 所谓临界区是指源代码中禁止两个线程同时操作的部分,即一次只有一个线程进入该区域,就是一次只能由一个线程来执行的一段代码。不过一直弄不明白临界区到底保护哪些资源,似乎只是定义中描述的“禁止两个线程同时操作”的代码。我的理解中,临界区似乎只能同步同一文件中定义的线程类的多个实例,它们才有进入同一临界区的可能。如果有线程类ThreadA、ThreadB,分别在不同的文件中被定义,即使在每个文件中都有同样命名为CriticalOK的全局临界区变量,似乎也不能达到同步的作用,互相之间应该没有任何影响。如果两个线程使用同一个ADOConnection对象执行数据库操作,则由于两个线程不能很好的同步,有可能造成的数据库占线。(问题六:这段描述自己感觉也不是很清楚,望各位高手指点迷津)
  2.互斥非常类似于临界区,除了两个关键的区别:首先,互斥可用于跨进程的线程同步(问题六补充:临界区不能跨进程,恐怕也不能跨线程(文件)吧)。其次,互斥能被赋予一个字符串名字,并且通过引用此名字创建现有互斥对象的附加句柄。
  根据上面描述引出问题七:两个线程同时使用同一个ADOConnection连接数据库进行操作会不会引起连接占线?这个和线程无关了,我在使用的时候发现会出现连接占线的情况,这时在应用程序的所有线程,包括主线程中通过使用互斥保证同一时间只有一个线程使用ADOConnection连接数据库操作--这样做法有没有太罗索了?是否必要?这样子的话,似乎程序一起动就应该创建这个互斥对象了。
  书中范例在程序中使用Wa i t F o r S i n g l e O b j e c t ( )来防止其他线程进入同步区域的代码,该函数等待返回的代码为WA I T _ O B J E C T _ 0,互斥对象处于发信号状态;但是如果返回了WA I T _ A B A N D O N E D,则互斥对象归当前状态所有且被设为非发信号状态。问题八:看书时,认为如果返回WAIT_ABANDONED,似乎也应该允许进入当前线程的同步区域呀?

  3.信号量 它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。目前编写的一些程序还没有复杂到需要使用信号量的地步,所以没有什么实际操作的经验。只是对信号量对象的名称、以及互斥对象的名称有些疑虑,问题九:信号量对象、互斥对象既然可以用于跨进程的线程同步,如果两个应用程序为自己的信号量命名了同一名称,但本意并不是想跨进程同步的,这时候由于信号量名称的缘故,岂不是会出乱子了?


这两天为了线程程序的问题,翻来覆去的看了几本书中关于线程的介绍。依然有些模糊,准备写代码测试一下子,也希望各位高手不吝赐教。

页: [1]
© 1999-2008 EvilOctal Security Team