扩展Delphi的线程同步对象
在编写多线程应用程序时 最重要的是控制好线程间的同步资源访问 以保证线程的安全运行 Win API提供了一组同步对象 如 信号灯(Semaphore) 互斥(Mutex) 临界区(CriticalSection)和事件(Event)等 用来解决这个问题 Delphi分别将事件对象和临界区对象封装为Tevent对象和TcritialSection对象 使得这两个对象的使用简单且方便 但是如果在Delphi程序中要使用信号灯或互斥等对象就必须借助于复杂的Win API函数 这对那些不熟悉Win API函数的编程人员来说很不方便 因此 笔者用Delphi构造了两个类 对信号灯和互斥对象进行了封装(分别为TSemaphore和TMutex) 希望对广大Delphi编程人员有所帮助 一 类的构造 我们先对Win API的信号灯对象和互斥对象进行抽象 构造一个父类THandleObjectEx 然后由这个父类派生出两个子类Tsemphore和Tmutex 类的源代码如下 unit SyncobjsEx; interface uses Windows Messages SysUtils Classes Syncobjs; type THandleObjectEx = class(THandleObject) // THandleObjectEx为互斥类和信号灯类的父类 protected FHandle: THandle; FLastError: Integer; public destructor Destroy; override; procedure Release; override; function WaitFor(Timeout: DWORD): aitResult; property LastError:Integer read FLastError; property Handle: THandle read FHandle; end; TMutex = class(THandleObjectEx)//互斥类 public constructor Create(MutexAttributes: PSecurityAttributes; InitialOwner: Boolean;const Name:string); procedure Release; override; end; TSemaphore = class(THandleObjectEx) //信号灯类 public constructor Create(SemaphoreAttributes: PSecurityAttributes; InitialCount:Integer; MaximumCount: integer; const Name: string); procedure Release(ReleaseCount: Integer= ;PreviousCount:Pointer=nil) overload; end; implementation { THandleObjectEx }//父类的实现 destructor THandleObjectEx Destroy; begin Windows CloseHandle(FHandle); inherited Destroy; end; procedure THandleObjectEx Release; begin end; function THandleObjectEx WaitFor(Timeout: DWORD): aitResult; //等待函数 参数为等待时间 begin case WaitForSingleObject(Handle Timeout) of WAIT_ABANDONED: Result := wrAbandoned; //无信号 WAIT_OBJECT_ : Result := wrSignaled; //有信号 WAIT_TIMEOUT: Result := wrTimeout;//超时 WAIT_FAILED://失败 begin Result := wrError; FLastError := GetLastError; end; else Result := wrError; end; end; { TSemaphore }//信号灯类的实现 constructor TSemaphore Create(SemaphoreAttributes: PSecurityAttributes; InitialCount MaximumCount: integer; const Name: string);//信号灯类的构造函数 begin FHandle := CreateSemaphore (SemaphoreAttributes InitialCount MaximumCount PChar(Name)); //四个参数分别为 安全属性 初始信号灯计数 最大信号灯计数 信号灯名字 end; procedure TSemaphore Release(ReleaseCount: Integer= ; PreviousCount:Pointer=nil); //信号灯类的Release方法 每执行一次按指定量增加信号灯计数 begin Windows ReleaseSemaphore(FHandle ReleaseCount PreviousCount); end; { TMutex }//互斥类的实现 constructor TMutex Create(MutexAttributes: PSecurityAttributes; InitialOwner: Boolean; const Name: string); //互斥类的构造函数 begin FHandle := CreateMutex(MutexAttributes InitialOwner PChar(Name)); end; procedure TMutex Release;//互斥类的Release方法 用来释放对互斥对象的所有权 begin Windows ReleaseMutex(FHandle); end; end; 二 信号灯对象与互斥对象的使用 信号灯对象 信号灯对象维持一个从 到指定最大值之间的数 在其计数大于 时是有信号的 而在其计数为 时是无信号的 信号灯对象可用来限制对共享资源进行访问的线程数量 例如应用程序可使用信号灯对象来限制它建立的窗口数量 用类的Create方法来建立信号灯对象 在调用该方法时 可以指定对象的初始计数和最大计数 该方法有四个参数 依次为 安全属性 初始计数 最大计数和对象名字(以便别的进程的线程可打开指定名字的信号灯句柄) 如 Semaphore := TSemaphore Create(nil ); 一般把信号灯的初始计数设置成最大值 每次当信号灯有信号并等待函数返回时 信号灯计数就会减 而通过调用对象的Release方法可按指定量增加信号灯的计数(默认为加 ) 计数值越小就表明访问共享资源的程序越多 如 Semaphore Release( nil); 其中第一个参数为增加的信号灯数量 第二个参数为执行该方法之前的信号灯数量 信号灯用法举例 if wrSignaled = Semaphore WaitFor( ) then//若信号灯是有信号的 begin //打开另一个窗口 end Semaphore Release() 在线程建立窗口之前 它使用WaitFor函数确定信号灯的当前计数是否允许建立新的窗口 等待时间设为 秒 互斥对象 Mutex对象的状态在它不被任何线程拥有时是有信号的 而当它被拥有时则是无信号的 Mutex对象很适合用来协调多个线程对共享资源的互斥访问(mutually exclusive) 例如 有几个线程共享对数据库的访问时 线程可以使用Mutex对象 一次只允许一个线程向数据库写入 用类的Create方法建立Mutex 对象 在建立Mutex 时 可以为对象起个名字 这样其他进程中的线程可以打开指定名字的Mutex对象句柄 例如 Mutex := TMutex Create(nil False ); 在完成对共享资源的访问后 可以调用Release方法来释放Mutex 以便让别的线程能访问共享资源 如果线程终止而不释放Mutex 则认为该Mutex被废弃 互斥对象用法举例如下 if wrSignaled = Mutex WaitFor( ) then//若获得互斥对象的拥有权 begin try //往数据库写入 finally Mutex Release;//释放对互斥对象的拥有权 end; end; lishixinzhi/Article/program/Delphi/201311/8521
Delphi 如何用多线程进行数据采集
就以下两个方面来讲解以下在delphi中如何用多线程进行数据采集:
---- 1. 多线程进行数据采集应解决的问题
---- 其实,多线程程序设计复杂是暂时的;如果,你采用传统的C进行多线程的设计,那么你必须自己控制线程间的同步。那将是很复杂的。但是,如果利用面向对象的设计方法,采用Delphi进行多线程程序设计,问题就简单多了。这是因为,Delphi已将多线程的复杂性替我们处理了,我们所要做的就是继承。
---- 具体地说,多线程数据采集需要完成以下工作:
---- ① 从TThread类派生一个自己的类SampleThread。这就是我们用于数据采集的类。进行采集时,只需要简单地创建一个SampleThread的实例。
---- ② 重载超类TThread的Execute方法。在这一方法中将具体地执行数据采集任务。
---- ③ 如果希望一边采集一边显示,就在编写几个用于显示采集进度的过程,供Execute方法调用。
---- TThread类中最常用的属性/方法如下:
Create方法:constructor Create
(CreateSuspended: Boolean);
---- 其中CreateSuspended参数确定线程在创建时是否立即执行。如果为True,新线程在创建后被挂起;如果为False,线程在创建后立即执行。
FreeOnTerminate属性:
property FreeOnTerminate: Boolean;
---- 该属性确定程序员是否负责撤消该线程。如果该属性为True,VCL将在该线程终止时自动撤消线程对象。它的缺省值为False。
OnTerminate属性:
property OnTerminate: TNotifyEvent;
---- 该属性指定一个当线程终止时发生的事件。
---- 下面看一个具体的例子:
---- 2. 多线程数据采集的实现
---- 这是笔者开发的一个测抽油机功图的程序。它的功能是采集抽油机悬点的载荷及位移数据,经过处理后做出抽油机的功图。图1(略)所示是数据采集时的界面。点“采集数据”按钮后,程序将创建一新的线程,并设置其属性。这一新线程将完成数据采集任务。程序如下:
Procedure TsampleForm.
DoSampleBtnClick(Sender: TObject);
Begin
ReDrawBtn.Enabled := True;
DoSampleBtn.Enabled := False;
FFTBtn.Enabled := True;
TheSampler := SampleThread.Create(False);
创建采集线程
TheSampler.OnTerminate := FFTBtnClick;
采集完成后要执行的任务
TheSampler.FreeOnTerminate := True;
采集完成后撤消
End;
---- 采集线程的类定义如下:
Type
SampleThread = class(TThread)
Public
function AdRead(ach: byte): integer; safecall;
读A/D卡的函数
procedure UpdateCaption;
显示采集所用时间
private
{ Private declarations }
protected
thes, thep: real;
dt: real;
id: integer;
st, ed: LongInt;
procedure Execute; override;
这是关键。
End;
---- 在这个类中定义了一个函数AdRead用于操作A/D卡,两个过程用于显示采集的进度与所用时间。需要注意的是AdRead函数是用汇编写的,参数调用格式必须是safecall。
---- 关键的重载方法Execute的代码如下:
Procedure SampleThread.Execute;
Begin
StartTicker := GetTickCount;
id := 0;
Repeat
thes := Adread(15) * ad2mv * mv2l;
采集第15通道
thep := Adread(3) * ad2mv * mv2n;
采集第3通道
dt := GetTickCount - StartTicker;
sarray[id] := thes;
parray[id] := thep;
tarray[id] := dt;
inc(id);
Synchronize(UpdateCaption);
注意:显示采集进度
Until id >=4096;
ed := GetTickCount;
Synchronize(ShowCostTime);
注意:显示所用时间
end;
---- 从以上代码中可见,Execute与一般的代码并无本质区别。仅有的区别是显示采集进度和显示所用时间时,不能直接调用各自的过程,而是通过调用Synchronize间接地调用。这样作是为了保持进程间的同步。
推荐阅读
- ○ CFO总变成CEO这背后是隐藏着什么秘密呢?
- ○ qq估价器在线查询
- ○ 淘宝店铺装修代码大全
- ○ 街拍齐b小短裙
- ○ 苹果12Pro参数
- ○ 淘宝返利网怎么用
- ○ acfun下载
- ○ 斗战神嗜血牛加点
- ○ baidu翻译
- ○ dnf悲叹之塔耳环
最新文章
- ○ CFO总变成CEO这背后是隐藏着什么秘密呢?
- ○ qq估价器在线查询
- ○ 淘宝店铺装修代码大全
- ○ 街拍齐b小短裙
- ○ 苹果12Pro参数
- ○ 淘宝返利网怎么用
- ○ acfun下载
- ○ 斗战神嗜血牛加点
- ○ baidu翻译
- ○ dnf悲叹之塔耳环