{所谓临界区,就是一次只能由一个线程来执行的一段代码。如果把初始化数组的代码放在临界区内,另一个线程在第一个线程处理完之前是不会被执行的。 使用临界区的步骤: 1、先声明一个全局变量类型为TRTLCriticalSection; 2、在线程Create()前调用InitializeCriticalSection()过程来初始化,该函数定义是: void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 类型lpCriticalSection即是Delphi封装的TRTLCriticalSection。 3、在线程的需要放入临界区的代码前面使用EnterCriticalSection(lpCriticalSection)过程来开始建立临界区。在代码完成后用LeaveCriticalSection(lpCriticalSection)来标志临界区的结束。 4、在线程执行完后用DeleteCriticalSection(lpCriticalSection)来清除临界区。这个清除过程必须放在线程执行完后的地方,比如FormDesroy事件中。上面的例子中,若把该过程放在TMyThread.Create(False);后,会产生错误。 } unit Tst_Thread3U; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private procedure ThreadsDone(Sender: TObject); end; TMyThread=class(TThread) protected procedure Execute;override; end; var Form1: TForm1;implementation{$R *.dfm} const MaxSize=128; var NextNumber:Integer=0; DoneFlags:Integer=0; GlobalArry:array[1..MaxSize] of Integer; Lock:byte; //1-不同步 2-临界区 3-互斥 CS:TRTLCriticalSection; //临界区 hMutex:THandle; //互斥function GetNextNumber:Integer; begin Result:=NextNumber; inc(NextNumber); end;procedure TMyThread.Execute; var i:Integer; begin FreeOnTerminate:=True; //终止后自动free OnTerminate:=Form1.ThreadsDone; if Lock<>3 then //非互斥情况 begin if Lock=2 then EnterCriticalSection(CS); //建立临界区 for i := 1 to MaxSize do begin GlobalArry[i]:=GetNextNumber; Sleep(5); end; if Lock=2 then LeaveCriticalSection(CS);//离开临界区 end else //-------互斥 begin if WaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then begin for i := 1 to MaxSize do begin GlobalArry[i]:=GetNextNumber; Sleep(5); end; end; ReleaseMutex(hMutex); //释放 end; end;procedure TForm1.ThreadsDone(Sender: TObject); var i:Integer; begin Inc(DoneFlags); if DoneFlags=2 then begin for i := 1 to MaxSize do Memo1.Lines.Add(inttostr(GlobalArry[i])); if Lock=2 then DeleteCriticalSection(CS); //删除临界区 If Lock=3 then CloseHandle(hMutex); //关闭互斥 end; end; //非同步 procedure TForm1.Button1Click(Sender: TObject); begin Lock:=1; TMyThread.Create(False); TMyThread.Create(False); end; //临界区 procedure TForm1.Button2Click(Sender: TObject); begin Lock:=2; InitializeCriticalSection(CS); //初始化临界区 TMyThread.Create(False); TMyThread.Create(False); end; //互斥 procedure TForm1.Button3Click(Sender: TObject); begin Lock:=3; // 互斥 hMutex:=CreateMutex(0,False,nil); TMyThread.Create(False); TMyThread.Create(False); end; end.
{所谓临界区,就是一次只能由一个线程来执行的一段代码。如果把初始化数组的代码放在临界区内,另一个线程在第一个线程处理完之前是不会被执行的。
使用临界区的步骤:
1、先声明一个全局变量类型为TRTLCriticalSection;
2、在线程Create()前调用InitializeCriticalSection()过程来初始化,该函数定义是:
void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
类型lpCriticalSection即是Delphi封装的TRTLCriticalSection。
3、在线程的需要放入临界区的代码前面使用EnterCriticalSection(lpCriticalSection)过程来开始建立临界区。在代码完成后用LeaveCriticalSection(lpCriticalSection)来标志临界区的结束。
4、在线程执行完后用DeleteCriticalSection(lpCriticalSection)来清除临界区。这个清除过程必须放在线程执行完后的地方,比如FormDesroy事件中。上面的例子中,若把该过程放在TMyThread.Create(False);后,会产生错误。
}
unit Tst_Thread3U;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
procedure ThreadsDone(Sender: TObject);
end;
TMyThread=class(TThread)
protected
procedure Execute;override;
end;
var
Form1: TForm1;implementation{$R *.dfm}
const
MaxSize=128;
var
NextNumber:Integer=0;
DoneFlags:Integer=0;
GlobalArry:array[1..MaxSize] of Integer;
Lock:byte; //1-不同步 2-临界区 3-互斥
CS:TRTLCriticalSection; //临界区
hMutex:THandle; //互斥function GetNextNumber:Integer;
begin
Result:=NextNumber;
inc(NextNumber);
end;procedure TMyThread.Execute;
var
i:Integer;
begin
FreeOnTerminate:=True; //终止后自动free
OnTerminate:=Form1.ThreadsDone;
if Lock<>3 then //非互斥情况
begin
if Lock=2 then EnterCriticalSection(CS); //建立临界区
for i := 1 to MaxSize do
begin
GlobalArry[i]:=GetNextNumber;
Sleep(5);
end;
if Lock=2 then LeaveCriticalSection(CS);//离开临界区
end else //-------互斥
begin
if WaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then
begin
for i := 1 to MaxSize do
begin
GlobalArry[i]:=GetNextNumber;
Sleep(5);
end;
end;
ReleaseMutex(hMutex); //释放
end;
end;procedure TForm1.ThreadsDone(Sender: TObject);
var
i:Integer;
begin
Inc(DoneFlags);
if DoneFlags=2 then
begin
for i := 1 to MaxSize do
Memo1.Lines.Add(inttostr(GlobalArry[i]));
if Lock=2 then DeleteCriticalSection(CS); //删除临界区
If Lock=3 then CloseHandle(hMutex); //关闭互斥
end;
end;
//非同步
procedure TForm1.Button1Click(Sender: TObject);
begin
Lock:=1;
TMyThread.Create(False);
TMyThread.Create(False);
end;
//临界区
procedure TForm1.Button2Click(Sender: TObject);
begin
Lock:=2;
InitializeCriticalSection(CS); //初始化临界区
TMyThread.Create(False);
TMyThread.Create(False);
end;
//互斥
procedure TForm1.Button3Click(Sender: TObject);
begin
Lock:=3; // 互斥
hMutex:=CreateMutex(0,False,nil);
TMyThread.Create(False);
TMyThread.Create(False);
end;
end.
互斥量:占用资源较多、速度较慢、系统资源、命名对象、可跨进程使用
临界区:占用资源较少、速度较快、进程资源、进程内使用简单来说就是一个标记,标志是否有线程在使用某个资源。
每个线程要使用这个资源就要把标志设置为True,当使用完毕之后就把它设置为False。而当标志本来就是True的时候就没法再设置为Ture,一直等待,直到等到它变为False后才能再次设置为True。