Delphi中使用多线程

这些天在Indy的阻塞式Socket模型的强迫下,开始在Delphi中使用多线程。总结了一些经验,尽管非常肤浅:

1、对于VCL的控件
大部分VCL的控件的方法和属性是不能保证线程安全的。我粗浅的理解线程安全为如果这个函数同时被两个线程调用时,由于内部的指令不能保证按顺序(即中间插入其他线程的指令执行)的执行,导致代码逻辑发生错误。
VCL自身给TThread提供了Synchronize函数,让用户用这个函数代理调用需要操作VCL的函数。根据网友的文章,其实Synchronize就是通过Windows的消息把这个代理调用的信息发送给主线程,然后让主线程来执行这个函数。并且在Synchronize执行时是等待着的,只有主线程有空处理这个消息并在处理完后Synchronize才会执行完毕。
使用Synchronize来处理下载线程与主线程的沟通问题一个是使用上的不方便。Synchronize只允许代理调用无参数的函数,这样使得用户必须用自定义一个类来包裹函数,很不方便。另外Synchronize的调用不好调试,且会阻塞下载线程,等待主线程处理完毕。
所以我采用的是自定义一个MessageQueue,让下载线程在需要通知主线程的时候,用一个事件回调主线程的一个函数,而这个函数只是把消息加入到MessageQueue。然后在主线程中用一个Timer来按时间清空处理MessageQueue中积压的消息。因为Timer是VCL控件,所以其调用是在主线程内的,不会有线程安全的问题了。而线程安全的问题移到了对MessageQueue身上,因为有可能很多个线程(以后会有多线程下载)同时Push消息。这个问题可以用TThreadList,再加一层Adapter变成Queue先进先出的模型。

2、对于自己的函数
自己写的函数是不能让Synchronize来帮助你处理线程安全的问题。回忆线程安全问题的根本起源就是写的时候假定了函数只被一个线程调用,从而内部的指令都是一条挨着一条顺序执行的。解决这个问题的办法有很多,加锁解锁就是一个。

3、总结
VCL的控件的函数与自己写的函数是没有什么差别的。不同指出是VCL一定是执行在主线程之中的。只要一个函数没有提供什么保护措施来保证线程安全,那么这个函数就不能被自身所在线程之外的其他线程调用。所以因此VCL只能在主线程中安全运行,其他线程要调用它就要使用Synchronize或者其他间接的措施。同样如果自己写函数没有保护措施,不能保证线程安全,它也一样不能被其他线程调用。
所以要保证线程安全,1、函数自身提供保护措施,2、调用者恪守规矩,不去碰这些函数,或者用比较绕的方式去用这些函数。对于自己写函数要线程安全,最好用第一个办法,对于VCL我们只能守好规矩了。

你可能感兴趣的:(Delphi)