在编写多线程应用程序时
最重要的是控制好线程间的同步资源访问
以保证线程的安全运行
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 WindowsMessagesSysUtilsClassesSyncobjs;
type
THandleObjectEx = class(THandleObject)
// THandleObjectEx为互斥类和信号灯类的父类
protected
FHandle: THandle;
FLastError: Integer;
public
destructor Destroy; override;
procedure Release;
override;
function WaitFor(Timeout: DWORD): TWaitResult;
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 THandleObjectExDestroy;
begin
WindowsCloseHandle(FHandle);
inherited Destroy;
end;
procedure THandleObjectExRelease;
begin
end;
function THandleObjectExWaitFor(Timeout: DWORD): TWaitResult;
//等待函数参数为等待时间
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 TSemaphoreCreate(SemaphoreAttributes: PSecurityAttributes;
InitialCount MaximumCount: integer; const Name: string);//信号灯类的构造函数
begin
FHandle := CreateSemaphore
(SemaphoreAttributesInitialCount MaximumCountPChar(Name));
//四个参数分别为安全属性初始信号灯计数最大信号灯计数信号灯名字
end;
procedure TSemaphoreRelease(ReleaseCount: Integer=; PreviousCount:Pointer=nil);
//信号灯类的Release方法每执行一次按指定量增加信号灯计数
begin
WindowsReleaseSemaphore(FHandle ReleaseCount PreviousCount);
end;
{ TMutex }//互斥类的实现
constructor TMutexCreate(MutexAttributes: PSecurityAttributes;
InitialOwner: Boolean; const Name: string);
//互斥类的构造函数
begin
FHandle := CreateMutex(MutexAttributes InitialOwner PChar(Name));
end;
procedure TMutexRelease;//互斥类的Release方法用来释放对互斥对象的所有权
begin
WindowsReleaseMutex(FHandle);
end;
end;
二信号灯对象与互斥对象的使用
信号灯对象
信号灯对象维持一个从到指定最大值之间的数在其计数大于时是有信号的而在其计数为时是无信号的信号灯对象可用来限制对共享资源进行访问的线程数量例如应用程序可使用信号灯对象来限制它建立的窗口数量
用类的Create方法来建立信号灯对象在调用该方法时可以指定对象的初始计数和最大计数该方法有四个参数依次为安全属性初始计数最大计数和对象名字(以便别的进程的线程可打开指定名字的信号灯句柄)如
Semaphore := TSemaphoreCreate(nil);
一般把信号灯的初始计数设置成最大值每次当信号灯有信号并等待函数返回时信号灯计数就会减而通过调用对象的Release方法可按指定量增加信号灯的计数(默认为加)计数值越小就表明访问共享资源的程序越多如SemaphoreRelease( nil);其中第一个参数为增加的信号灯数量第二个参数为执行该方法之前的信号灯数量
信号灯用法举例
if wrSignaled = SemaphoreWaitFor() then//若信号灯是有信号的
begin
//打开另一个窗口
end
SemaphoreRelease()
在线程建立窗口之前它使用WaitFor函数确定信号灯的当前计数是否允许建立新的窗口等待时间设为秒
互斥对象
Mutex对象的状态在它不被任何线程拥有时是有信号的而当它被拥有时则是无信号的Mutex对象很适合用来协调多个线程对共享资源的互斥访问(mutually exclusive)例如有几个线程共享对数据库的访问时线程可以使用Mutex对象一次只允许一个线程向数据库写入
用类的Create方法建立Mutex 对象在建立Mutex 时可以为对象起个名字这样其他进程中的线程可以打开指定名字的Mutex对象句柄例如
Mutex := TMutexCreate(nil False );
在完成对共享资源的访问后可以调用Release方法来释放Mutex以便让别的线程能访问共享资源如果线程终止而不释放Mutex则认为该Mutex被废弃
互斥对象用法举例如下
if wrSignaled = MutexWaitFor() then//若获得互斥对象的拥有权
begin
try
//往数据库写入
finally
MutexRelease;//释放对互斥对象的拥有权
end;
end;
上述类代码在Windows Delphi 下调试通过