C+++Builder下的多线程编程
来源:微智科技网
亥岸f f与RWC ++ Builder下的多线程编程王峰(电子第54研究所石家庄050081)摘要 介绍了使用C+十Builder实现多线程编程的方法,包括了线程的定义、执行和同步。着重介绍了多线程之间的同步协调问题。关键词 C++Builder线程同步1概述#pragma package(smatr_init)//一一一一一一一一一一一一一一一一一一一一一 Inprise公司的新一代RAD开发工具C+十__fastcall MyThread:MyThread(bool CreateSuspended):TI'hread( CreateSuspended)Builder,可以方便地实现多线程的编灌。! C + + Builder通过VCL提供了一些用于简化编Priority=tpldle; //指定线程优先级FreeOnTerminate = true;//线程结束后自动写多线程应用程序的对象,如TThread对象。从而释放使得编写多线程应用程序变得非常容易。应用程序| UJ中使用多线程可以从以下途径来增强程序的功能:VO __fastcall MyThread::Execute()| .避免瓶颈。若进程只有一个线程,那么有时 //一一一一Pl ace thread code here一一一一程序可能会必须停止其它所有的动作以等待某一费} 时的线程的执行。在该线程完成前,CPU始终是空这样线程的基本框架已经完成,我们只要在线 闲的。使用多线程,应用程序就能在某一个线程等程的Ex ecute)函数中添加任务代码,TMyThread对待费时进程的结果时,继续执行其它的线程。象就可以使用了。上面代码中除黑体字代码外,均 .组织程序。通常可以将线程的行为组织为 为自动产生的代码。 几个功能的并行进程。使用线程可同步执行每.初始化线程 个并行进程中的单段代码。使用线程还可指定多个为了保证线程稳定可靠的运行,需要使用线程 构造函数初始化线程类,指定线程的优先级和何时程序任务的优先级,以便把更多CPU时间分配给更释放线程。优先级是指当操作系统在所有线程中分重要的任务。配CPU时间段时,指示线程可得到多少。要指定线2线程的定义程的优先级,可设置Priority属性。Priority属性值有7个选择,如附表所示。 .线程的创建要在应用程序中使用线程对象,必须创建 附表线程优先级的定义TThread的一个新的派生类。为创建TThread的一个属性值优先级派生类,可从主菜单中选择File I New。在新对象对Tpldle 线程只在系统空闲时运行。话框中,选择Thread Object。系统会提示为新线程对Windows不会中断其它线程来执象提供类名。在提供名字之后,C十+Builder创建行带有tpldle优先级的线程。一个新的.cpp和头文件以实现线程。假如我们的TpLowest程序优先级比标准低两个点。线程对象起名为MyThread,则当前工程中将自动增TpLower程序优先级比标准低一个点。加建一个名为TMyThread的TThread子类和一个名TpNormal程序有标准优先级。为Unit2. cpp的单元,这就是我们创建的TMyTheradTpHigher程序优先级比标准高一个点。子类的原码,如下:TpHighest程序优先级比标准高两个点。#i nclude<vcl\vcl. h>程序得到最高的优先级。#pr agma hdrstopTpTimerCritical#i nclude "Unit2. h"2002年布28卷常2期夕己线电3甩佑技木淤岸fliff汽irt' 当线程完成其操作,就可简单地被释放。最方便地就是让线程对象释放其本身。为此,应将_finallypLockXY一>Release);FreeOnTerminate属性设为ture。参见上面代码的构造函数中的黑体代码行。.编写线程函数 Execut e方法就是线程函数。编写线程函数必须确认没有覆盖应用程序其它线程所使用的内存。另一方面,因为线程与其它线程共享相同的进程空间,可使用共享内存在线程之间通信。上例中有一个重要区段LockXY,可阻止访问全 局变量x和y。任何使用x和y的线程必须调用重要区段。通过异常捕获可以保证在发生异常时可以释放重要区段,而允许其它线程访问全局变量x和y。需要强调的是,重要区段只在每个线程都使用它们来访问关联的全局内存时才有用。忽略重要区段3线程的协调 当编写线程执行时运行的代码时,必须考虑到可能同步执行的其它线程的行为。要避免多个线程同时使用相同的全局对象或变量。另外,一个线程的执行可能依赖其它线程执行的结果。并且不调用Acquie而访问全局内存,r会引起同时访问的问题。 ③使用多重读、独占写的同步器当需要访问的是一个经常读但很少写的对象或 变量时,可以使用TMultiReadExclusiveWrite Synchro-nizer保护它。这个对象与重要区段类似,但它允许多个线程同时读,只要没有线程写即可。④使用主VCL线程 C + +Bui lder编程是建立在VCL类库的基础上的。在程序中经常需要访问VCL对象的属性和方法。不幸的是,VCL类库并不保证其中对象的属性和方法是线程访问安全的(Thread-safe),访问VCL对象的属性或调用其方法可能会访问到不被别的线程所保护的内存区域而产生错误。因此,Thread对了.1逻旁厚对厉4 为避免在访问全局对象或变量时与其它线程冲突,可能需要暂停其它线程的执行,直到该线程代码完成操作。我们主要介绍多线程共享数据的几种方法。 ①锁定对象一些对象内置了锁定能力以防止其它线程使用 该对象的实例。例如,画布对象(TCa nvas及其派生类)有一种Lock方法可防止其它线程访问画布,直到调用Un-Lock方法。VCL还包含一种线程安全的列表对象1TreadList。调用TThreadList : : LockList返回列表对象,同时阻止其它线程使用列表直到调用UnlockList方法。调用TCanvas : : Lock或TThreadList : : LockUst可以安全地嵌套。锁定直到最后一个锁定调用匹配到同一线程时才会被释放。②使用重要区段 多线程中在访问共同的公共数据块时,必须对 公共数据块进行保护。同时只允许一个线程对它的访问。这可以通过重要区段(Critical Section)的使用来实现,C ++ Builder中,给我们提供了一个TCriti-calSection对象来进行重要区段的划定。该对象有两象提供了一个Synchronize方法,当需要在线程中访问VCL对象属性或调用方法时,通过Synchronize方法来访问属性或调用方法就能避免冲突,使各个线程之间协调而不会产生意外的错误。如下所示:v oid__fastcall TMyThread:PushTheButton(void)} But tonl一>Click( );} v oid__fastcall TMyThread::Execute(){ )PushTheButton);Synchronize( (TThreadMethod} 个方法,Acquire)和Release( )。它设定的临界区域可以保证一次只有一个线程对该区域进行访问。如下例所示:pL ockXY一>Acquire();try|对But tonl一>Click)方法的调用就是通过Syn-chronize()方法来实现的,它可以自动避免发生多线程访问冲突。在C ++ Builder中,虽然有一些VCL对象也是线程访问安全的(如TFont, Teen, TBrush等),可以不用Sychronize()方法对它们的属性方法Y=sin(x);进行访问调用以提高程序性能,但是,对于更多的无(下转第40页) RADIO COMMUNICATIONS TECHNOLOGYVol. 28No.22002理位置不同而有所差异;③环境因素。不同的气侯环境,将直接影响所 测信号的[C/T] RB值; ④参考基准。参考地球站G/T值及天线增益值的准确性、可靠性;⑤噪声测量的随机性; ⑥人为因素。待测站和参考站应调试到最佳 状态。用频谱仪的AVG功能键,设置N ,100次,是减小噪声测试误差的有效方法;⑤制定科学、严谨的测试规范,提供准确、可靠的参考站G/T值及天线增益数据;⑥选择信标无调制时进行测试。这样可有效地减少测试误差。5结束语 本文所述的卫星信标比较法已第一次应用于天线增益及G/T值的测试,结果令人满意,测试方法得到众专家的认可。1 Wilbur L. Pritchard, Henri G. Suyderhoud, Robert A. Nel- 针对上述原因,采取如下措施:①异地同时测试,限地域选择测试参考站可有效减少地域因素、环境因素误差。地域范围以〔EIRP ] SB值、气候条件相同为准;②同地同时测试是最佳选择方案,可消除时间因素、地域因素、环境因素引人的测试误差;③同地不同时测试,无测试系统差异引人的误差,时间因素的测试误差,可通过多次测试,取其均方值;④采t ion)参考文献 s on. Satellite Communication Systems Engineering (Second Edi-2吕洪生等主编.实用卫星通信工程.成都:电子科技大学出版社,1 994.10踌令玲仓玲令玲f<玲C1x}玲导玲仓玲令玲E}特E<玲E<玲令特令玲令玲导玲仑特导玲导玲E<玲E<玲Ee玲令玲仑玲份玲令减令玲令玲份月令特仓玲C<*C4片令玲令玲令玲守特令玲仑玲守玲C}对令玲e玲C}玲令玲令玲C}玲令玲令玲份(上接第30页)TMy Thread‘MyProcess = new TMyThread (false);法确定的VCL对象,还是强烈建议使用Synchronize()方法确保程序的可靠性。需要注意的是不要在应用程序中创建太多的线 程,过多的线程反而会降低整体效率。3.2多窦窟I,17)1何步 若线程必须等到另一线程完成某项任务,可让线程暂时中断执行。然后,或者等待另一线程完全执行结束,或者等待另一线程通知完成了该项任务。①等待线程执行结束 可以使用WaitFor方法等待另一线程的结束。WaitFor直到那个线程终止才返回,终止的方式要么完成了其Execute方法,要么由于一个异常。②等待任务完成 当只需等待一些操作完成而不是等待线程结束 时,可以使用事件对象(TEvent ),该变量必须全局可见。假如A线程完成某些操作后,B线程才能执行,可以在A线程完成完成这些操作后,调用TEvent5工程应用 在国家某重点工程中,笔者负责开发接收分系统的监控软件。要求同时监控几十个检测控制点,同时和12个串行口通信,其中有的串口实时性要求较高,数据量较大。采用传统的编程一方法存在通信数据丢失、查询刷新时间长、命令响应慢等问题。为解决这些问题,采用了多线程技术,通讯口的读写、监控点查询和画面刷新均采用了的线程完成,监控效率大为提高,命令响应和数据采集间隔时间缩短,保证了监控数据的实时上报和下达,稳定可靠地完成了监控任务。6结束语本文结合Bor land公司开发的强大的RAD工具SetEvent,通知B线程操作完成。B线程检测到后,要调用TEvent : : ResetEvent关掉信号。C ++ Builder,对Window,下的多线程编程做了比较全面的介绍。多线程编程在软件开发中经常使用,4线程的执行 线程的执行由Execute方法实现。在程序中,首先创建线程类的实例,要创建一个立即开始运行的合理正确地使用可以大幅提高软件的性能和执行效率。线程实例,将构造函数的CreateSuspended参数设为false即可。例如,下列代码创建一个线程并开始运行:工业出版社,2000 参考文献 1 C ++ Builders开发人员指南.Borland/Inorise公司.机械RADIO COMMUNICATIONS TECHNOLOGYVol. 28 No. 2 2002