多線程編程(8) - 多線程同步之 CriticalSection(臨界區(qū))
先看一段程序, 代碼文件: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 Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function MyThreadFun(p: Pointer): DWORD; stdcall;
var
i: Integer;
begin
for i := 0 to 99 do Form1.ListBox1.Items.Add(IntToStr(i));
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;
end;
end.
窗體文件:object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 154
ClientWidth = 214
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object ListBox1: TListBox
Left = 9
Top = 9
Width = 121
Height = 97
ItemHeight = 13
TabOrder = 0
end
object Button1: TButton
Left = 131
Top = 112
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
end
在這段程序中, 有三個(gè)線程幾乎是同時(shí)建立, 向窗體中的 ListBox1 中寫數(shù)據(jù), 最后寫出的結(jié)果是這樣的:
能不能讓它們別打架, 一個(gè)完了另一個(gè)再來? 這就要用到多線程的同步技術(shù).
前面說過, 最簡(jiǎn)單的同步手段就是 "臨界區(qū)".
先說這個(gè) "同步"(Synchronize), 首先這個(gè)名字起的不好, 我們好像需要的是 "異步"; 其實(shí)異步也不準(zhǔn)確...
管它叫什么名字呢, 它的目的就是保證不**、有次序、都發(fā)生.
"臨界區(qū)"(CriticalSection): 當(dāng)把一段代碼放入一個(gè)臨界區(qū), 線程執(zhí)行到臨界區(qū)時(shí)就獨(dú)占了, 讓其他也要執(zhí)行此代碼的線程先等等; 這和前面用的 Lock 和 UnLock 差不多; 使用格式如下:
var CS: TRTLCriticalSection; {聲明一個(gè) TRTLCriticalSection 結(jié)構(gòu)類型變量; 它應(yīng)該是全局的}
InitializeCriticalSection(CS); {初始化}
EnterCriticalSection(CS); {開始: 輪到我了其他線程走開}
LeaveCriticalSection(CS); {結(jié)束: 其他線程可以來了}
DeleteCriticalSection(CS); {刪除: 注意不能過早刪除}
//也可用 TryEnterCriticalSection 替代 EnterCriticalSection.
用上臨界區(qū), 重寫上面的代碼, 運(yùn)行效果圖:
代碼文件: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.
聯(lián)系客服