Delphi多线程之Semaphore(信号对象)
之前已经有了两种多线程的同步方法:
CriticalSection(临界区)和Mutex(互斥),这两种同步方法差不多,只是作用域不同; CriticalSection(临界区)类似于只有一个蹲位的公共厕所,只能一个个地进;
Mutex(互斥)对象类似于接力赛中的接力棒,某一时刻只能一个人持有,谁拿着谁跑.
什么是Semaphore(信号或叫信号量)呢?
譬如到银行办业务、或者到车站买票,原来只有一个服务员,不管有多少人排队等候,业务只能一个个地来.
假如增加了业务窗口,可以同时受理几个业务呢?
这就类似与Semaphore对象,Semaphore可以同时处理等待函数(如:WaitForSingleObject)申请的几个线程.
Semaphore的工作思路如下:
1、首先要通过CreateSemaphore(安全设置,初始信号数,信号总数,信号名称)建立信号对象;
参数四:和Mutex一样,它可以有个名称,也可以没有,本例就没有要名称(nil);有名称的一般用于跨进程.
参数三:信号总数,是Semaphore最大处理能力,就像银行一共有多少个业务窗口一样;
参数二:初始信号数,这就像银行的业务窗口很多,但打开了几个可不一定,如果没打开和没有一样;
参数一:安全设置和前面一样,使用默认(nil)即可.
2、要接受Semaphore服务(或叫协调)的线程,同样需要用等待函数(如:WaitForSingleObject)排队等候;
3、当一个线程使用完一个信号,应该用ReleaseSemaphore(信号句柄,1,nil)让出可用信号给其他线程;
参数三:一般是nil,如果给个数字指针,可以接受到此时(之前)总共闲置多少个信号;
参数二:一般是1,表示增加一个可用信号;
如果要增加CreateSemaphore时的初始信号,也可以通过ReleaseSemaphore.
4、最后,作为系统内核对象,要用CloseHandle关闭.
另外,在Semaphore的总数是1的情况下,就和Mutex(互斥)一样了.
在本例中,每点击按钮,将建立一个信号总数为5的信号对象,初始信号来自Edit1;同时有5个线程去排队.
本例也附上了Delphi中TSemaphore类的例子,但没有过多地纠缠于细节,是为了尽快理出多线程的整体思路.
--------------------------------------------------------------------------------
本例效果图:
--------------------------------------------------------------------------------
代码文件:
--------------------------------------------------------------------------------
unit Unit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms, Dialogs,StdCtrls;
type
TForm1=class(TForm)
Button1:TButton;
Edit1:TEdit;
procedure Button1Click(Sender:TObject);
procedure FormCreate(Sender:TObject);
procedure FormDestroy(Sender:TObject);
procedure Edit1KeyPress(Sender:TObject;var Key:Char);
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
var
f:Integer;{用这个变量协调一下各线程输出的位置} hSemaphore:THandle;{信号对象的句柄}
function MyThreadFun(p:Pointer):DWORD;stdcall;
var
i,y:Integer;
begin
Inc(f);
y:=20*f;
if WaitForSingleObject(hSemaphore,INFINITE)=WAIT_OBJECT_0then begin
for i:=0to1000do
begin
Form1.Canvas.Lock;
Form1.Canvas.TextOut(20,y,IntToStr(i));
Form1.Canvas.Unlock;
Sleep(1);{以免Canvas忙不过来}
end;
end;
ReleaseSemaphore(hSemaphore,1,nil);
Result:=0;
end;
procedure TForm1.Button1Click(Sender:TObject);
var
ThreadID:DWORD;
begin
{不知是不是之前创建过Semaphore对象,假如有先关闭} CloseHandle(hSemaphore);
{创建Semaphore对象}
hSemaphore:=CreateSemaphore(nil,StrToInt(Edit1.Text),5,nil); Self.Repaint;
f:=0;
CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);
end;
{让Edit只接受12345五个数}
procedure TForm1.Edit1KeyPress(Sender:TObject;var Key:Char); begin
if not CharInSet(Key,['1'..'5'])then Key:=#0;
end;
procedure TForm1.FormCreate(Sender:TObject);
begin
Edit1.Text:='1';
end;
procedure TForm1.FormDestroy(Sender:TObject);
begin
CloseHandle(hSemaphore);
end;
end.
--------------------------------------------------------------------------------窗体文件:
--------------------------------------------------------------------------------
object Form1:TForm1
Left=0
Top=0
Caption='Form1'
ClientHeight=140
ClientWidth=192
Color=clBtnFace
Font.Charset=DEFAULT_CHARSET
Font.Color=clWindowText
Font.Height=-11
https://www.doczj.com/doc/b517986899.html,='Tahoma'
Font.Style=[]
OldCreateOrder=False
OnCreate=FormCreate
PixelsPerInch=96
TextHeight=13
object Button1:TButton
Left=109
Top=107
Width=75
Height=25
Caption='Button1'
TabOrder=0
OnClick=Button1Click
end
object Edit1:TEdit
Left=109
Top=80
Width=75
Height=21
TabOrder=1
Text='Edit1'
OnKeyPress=Edit1KeyPress
end
end
--------------------------------------------------------------------------------
再用SyncObjs单元下的TSemaphore类实现一次,使用方法差不多,运行效果也一样: --------------------------------------------------------------------------------
unit Unit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls;
type
TForm1=class(TForm)
Button1:TButton;
Edit1:TEdit;
procedure Button1Click(Sender:TObject);
procedure FormCreate(Sender:TObject);
procedure FormDestroy(Sender:TObject);
procedure Edit1KeyPress(Sender:TObject;var Key:Char);
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
uses SyncObjs;
f:Integer;
MySemaphore:TSemaphore;
function MyThreadFun(p:Pointer):DWORD;stdcall;
var
i,y:Integer;
begin
Inc(f);
y:=20*f;
if MySemaphore.WaitFor(INFINITE)=wrSignaled then
begin
for i:=0to1000do
begin
Form1.Canvas.Lock;
Form1.Canvas.TextOut(20,y,IntToStr(i));
Form1.Canvas.Unlock;
Sleep(1);
end;
end;
MySemaphore.Release;
Result:=0;
end;
procedure TForm1.Button1Click(Sender:TObject);
var
ThreadID:DWORD;
begin
if Assigned(MySemaphore)then MySemaphore.Free; MySemaphore:=TSemaphore.Create(nil,StrToInt(Edit1.Text),5,''); Self.Repaint;
f:=0;
CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID); CreateThread(nil,0,@MyThreadFun,nil,0,ThreadID);
end;
{让Edit只接受12345五个数}
procedure TForm1.Edit1KeyPress(Sender:TObject;var Key:Char); begin
if not CharInSet(Key,['1'..'5'])then Key:=#0;
end;
procedure TForm1.FormCreate(Sender:TObject);
begin
Edit1.Text:='1';
procedure TForm1.FormDestroy(Sender:TObject);
begin
if Assigned(MySemaphore)then MySemaphore.Free;
end;
end.
--------------------------------------------------------------------------------原文地址:https://www.doczj.com/doc/b517986899.html,/book/7/