delphi中实现多线程有两种方式:
1:直接调用windows的API函数:这种方式要求熟悉多线程的API函数,个人倾向于使用这种方式。在使用这种方式实现多线程时要特别注意API函数中参数的设置,对于API函数中各个参数的意义建议参考windows的联机帮助文档,这个是最权威的文档,其他都是浮云。
2:通过继承delphi的TThread类:TThread类以默认参数的方式封装了大部分的windows的API函数,但也有一些是没有封转的,比如多线程同步相关的API函数,对于这些函数,还是需要在程序中去手动调用的。在使用这种方式实现多线程时主要是重写create函数和Execute函数。在重写create函数时不要忘记加上Inherited Create(CreateSuspended),当CreateSuspended为true时初始化线程后线程处于挂起状态,需要通过Resume方法启动线程执行Execute方法;为false时线程处于运行状态,此时将立即启动线程执行Execute方法,通过Suspend方法可以挂起一个正在执行的线程。Execute方法中是线程执行时运行的代码,在该方法中一定要不断的检查Terminated属性的值以确保线程正常退出。同时建议设置FreeOnTerminate属性值为true,即当Execute方法执行完毕后自动销毁线程对象。
delphi中sleep函数的使用:当在一个线程中(包括主线程)使用sleep(time)函数时会使当前线程挂起time ms后再由cpu分配时间片给当前线程,当time=0时当前线程也会拒绝cpu当前分配给它的时间片并使自己处于挂起状态,当cpu下一次分配时间片给它时再启动。
多线程同步的实现方式(参考万一的博客,非常崇拜万一大牛):
1:临界区:临界区是最简单也最常用的同步多线程的方式,它是将程序中的一段代码放到临界区中,若有一个线程进入到临界区中执行代码,其他线程就无法再进入到临界区执行该段代码,除非前一个线程退出临界区。临界区方式只能同步某一个进程中的线程,即临界区不能通过跨进程来同步多线程,但使用临界区有一个好处就是对cpu时间片的消耗少,大概14-15个时间片(从别处看的,不知道他们怎么得出这个数据)
2:互斥对象(Mutex):互斥对象可以跨进程,是一个内核对象,它对cpu时间片的消耗比较大。哪个线程拥有了该互斥对象它就能运行,其他线程必须等拥有互斥对象的线程释放该互斥对象后才有机会拥有互斥对象并运行。一个互斥对象一次只能被一个线程拥有,线程通过API函数WaitForSingleObject来申请获得互斥对象。
3:信号量(semaphore):信号量是在互斥对象的基础上发展而来的,也是跨进程的,是内核对象,同样对cpu时间片的消耗比较大。但信号量一次可以被多个线程拥有,具体数据可以设置,当有线程申请到信号量后信号量数就减1,释放信号量后信号量数就加1,当信号量数位0时线程无法再申请到信号量了。线程同样通过API函WaitForSingleObject来申请获得信号量。
4:事件对象(Event):据说是多线程最原始和最灵活的手段,其灵活性在于可以随时启动和挂起事件对象,也可以设置事件对象执行一次立即停止。线程同样通过API函WaitForSingleObject来申请获得事件对象。
5:等待定时器对象(WaittableTimer):这个对象比较复杂,其基本理念是让等候的线程以指定的时间和时间间隔运行,比如让线程在指定的时间点每隔指定的时间间隔运行一次。该处涉及到回调函数的使用,没搞懂为什么要使用回调函数,我想可能是用回调函数更便于程序的维护吧。注意使用等待定时器对象时相关参数的意义及使用方法。线程同样通过API函WaitForSingleObject来申请获得等待定时器对象。
总结:针对不同的实现方式,应该根据具体程序的需要来选择,不要去盲目的使用。
VCL对象的同步:delphi中的VCL对象大多不是线程安全的,所以若要在附属线程中使用主线程中的VCL对象,需要通过Synchronize来同步,此时实际上是通过主线程来操作VCL对象的,它有一套自己的具体实现机制;另外对于像Canvas这样的对象的同步,可以使用lock和unlock方法来实现同步。
delphi中用多线程实现数据库操作:
1:BDE方式:对于通过BDE实现的数据库操作,在使用多线程实现时需要为每一个线程中的TQuery或TTable配置一个TSession对象,以保持对数据库中数据的同步。在正常使用中,即没有通过多线程来操作数据库时,delphi会默认为我们创建一个TSession对象,无需我们手动添加;但在用多线程实现对数据库的操作时因为要保证数据库中数据的同步,我们需要手动为每一个线程中的TQuery或者TTable对象设置TSession。
2:ADO方式:据说ADO方式有对多线程处理的代码,无需为每一个线程指定一个TSession,与正常方式连接数据库一样。但ADO方式在通过多线程操作数据库时好像有bug,具体情况我没遇到过,听我导师说的。
总结:无论以哪种方式通过多线程实现对数据库的操作,都必须注意在将数据通过数据感知组件显示时要注意的问题,此时只能在数据集打开成功后才能通过datasource将数据集连接到数据感知组件,并且对数据感知组件的操作需要通过Synchronize来同步。其实没有必要通过多线程方式来对数据库进行操作,在ADO方式下通过Recordset操作数据集的速度就应该算是非常快了,另外也可以通过OCI的方式来加快对oracle数据库的操作。