前面說過, 最簡單的同步手段就是 "臨界區".
先說這個 "同步"(Synchronize), 首先這個名字起的不好, 我們好像需要的是 "異步"; 其實異步也不准確...
管它叫什麼名字呢, 它的目的就是保證不沖突、有次序、都發生.
"臨界區"(CriticalSection): 當把一段代碼放入一個臨界區, 線程執行到臨界區時就獨占了, 讓其他也要執行此代碼的線程先等等; 這和前面用的 Lock 和 UnLock 差不多; 使用格式如下:
var CS: TRTLCriticalSection; {聲明一個 TRTLCriticalSection 結構類型變量; 它應該是全局的}
InitializeCriticalSection(CS); {初始化}
EnterCriticalSection(CS); {開始: 輪到我了其他線程走開}
LeaveCriticalSection(CS); {結束: 其他線程可以來了}
DeleteCriticalSection(CS); {刪除: 注意不能過早刪除}
//也可用 TryEnterCriticalSection 替代 EnterCriticalSection.
用上臨界區, 重寫上面的代碼, 運行效果圖:
代碼文件:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
CS: TRTLCriticalSection;
function MyThreadFun(p: Pointer): DWord; stdcall;
var
i: Integer;
begin
EnterCriticalSection(CS);
for i := 0 to 99 do Form1.ListBox1.Items.Add(IntToStr(i));
LeaveCriticalSection(CS);
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ID: DWord;
begin
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.Align := alLeft;
InitializeCriticalSection(CS);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeleteCriticalSection(CS);
end;
end.
Delphi 在 SyncObJS 單元給封裝了一個 TCriticalSection 類, 用法差不多, 代碼如下:unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses SyncObJS;
var
CS: TCriticalSection;
function MyThreadFun(p: Pointer): DWord; stdcall;
var
i: Integer;
begin
CS.Enter;
for i := 0 to 99 do Form1.ListBox1.Items.Add(IntToStr(i));
CS.Leave;
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ID: DWord;
begin
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.Align := alLeft;
CS := TCriticalSection.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
CS.Free;
end;
end.