现在的位置: 首页 > 综合 > 正文

◆Delphi多线程编程之五不同类线程读写全局变量-阻塞和锁定◆

2013年09月10日 ⁄ 综合 ⁄ 共 3294字 ⁄ 字号 评论关闭

 

Delphi多线程编程之五不同类线程读写全局变量-阻塞和锁定◆(乌龙哈里2008-10-13

(调试环境:Delphi2007+WinXPsp3 例程:Tst_Thread5.dpr

    前面的例子都是同类线程的不同实例来读写全局变量,用临界区、互斥等来锁住同段代码。现在碰到的问题是,A,B两个不同类型的线程,如何安全地来读写全局变量。

unit Tst_Thread5U;

 

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls,SyncObjs;

type

  TForm1 = class(TForm)

    Memo1: TMemo;

    Button1: TButton;

    Button2: TButton;

    Button3: TButton;

    procedure Button1Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure Button3Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

  TFirstThread=Class(TThread)

  protected

    procedure Execute;override;

    procedure ShowNum;

  end;

  TSecondThread=Class(TThread)

  protected

    procedure Execute;override;

    procedure ShowNum;

  end;

var

  Form1: TForm1;

implementation

{$R *.dfm}

 

const

  MaxSize=12;

var

  WhichRun:integer;

  GlobalArry:array[1..MaxSize] of Integer;

  LockCS:TCriticalSection; //uses SyncObjs

  LockMREWS:TMultiReadExclusiveWriteSynchronizer;  //uses SysUtils

//===============

procedure AddNum;

var

  i,j:integer;

begin

  if WhichRun=2 then LockCS.Acquire;

  if WhichRun=3 then LockMREWS.BeginRead;

  j:=GlobalArry[MaxSize];

  if WhichRun=3 then LockMREWS.EndRead;

 

  if WhichRun=3 then LockMREWS.BeginWrite;

 

  for i := 1 to MaxSize do

  begin

    GlobalArry[i]:=j;

    inc(j);

    Sleep(5);

  end;

  if WhichRun=2 then LockCS.Release;

  if WhichRun=3 then LockMREWS.EndWrite;

end;

 

procedure TFirstThread.Execute;

begin

  FreeOnTerminate:=True;

  AddNum;

  Synchronize(ShowNum);

end;

procedure TFirstThread.ShowNum;

var

  i:integer;

begin

  for i := 1 to MaxSize do

    Form1.Memo1.Lines.Add(inttostr(GlobalArry[i]));

end;

 

procedure TSecondThread.Execute;

begin

  FreeOnTerminate:=True;

  AddNum;

  Synchronize(ShowNum);

end;

procedure TSecondThread.ShowNum;

var

  i:integer;

begin

  for i := 1 to MaxSize do

    Form1.Memo1.Lines.Add(inttostr(GlobalArry[i]));

end;

//未阻塞

procedure TForm1.Button1Click(Sender: TObject);

begin

  WhichRun:=1;

  TFirstThread.Create(False);

  TSecondThread.Create(False);

end;

//阻塞 TCriticalSection

procedure TForm1.Button2Click(Sender: TObject);

begin

  WhichRun:=2;

  TFirstThread.Create(False);

  TSecondThread.Create(False);

end;

//TMREWS

procedure TForm1.Button3Click(Sender: TObject);

begin

  WhichRun:=3;

  TFirstThread.Create(False);

  TSecondThread.Create(False);

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

  LockCS:=TCriticalSection.Create;

  LockMREWS:=TMultiReadExclusiveWriteSynchronizer.Create;

end;

 

procedure TForm1.FormDestroy(Sender: TObject);

begin

  LockCS.Free;

  LockMREWS.Free;

end;

end.

 

一、用TCriticalSection类来阻塞。ps:这里的咚咚都涉及Win32编程,我对这些不了解,先掌握如何运用吧。)这个有点类似临界区。Uses SyncObjs单元

1、声明一个全局的TCriticalSection类的实例。

2、建立TCriticalSection.Create,最好是在程序onCreate里面,这样才能保证对所有线程进行控制。

3、在全局变量访问前用TCriticalSection.AcquireTCriticalSection.Enter来阻塞。

4、访问完毕,用TCriticalSection.ReleaseTCriticalSection.Leave来解除阻塞。

5、在恰当的位置进行TCriticalSection.Free,一般在程序的onDestroy里。

 

二、用TMultiReadExclusiveWriteSynchronizer类来阻塞。可以写成TMREWSync这个类在SysUtils单元里。(ps:天哪,那么长的单词我第一次见)TMultiReadExclusiveWriteSynchronizerTCriticalSection不同的是,它允许多个线程同时读一个变量,只是在写一个变量时才需要事先阻塞,因为只有多个线程同时写一个变量才有可能造成冲突。

使用TMREWS的优势是它允许多线程的并发读取,同时又与CriticalSection一样允许读的时候只有一个线程访问。劣势是TMREWS用起来要费更高的代价。

 

1、声明一个全局的TMultiReadExclusiveWriteSynchronizer类的实例。

2、建立TMultiReadExclusiveWriteSynchronizer.Create

3、每个线程在读一个全局变量前要先调用该类的BeginRead()来检查是否有其他线程在写这个变量。如果有,就

抱歉!评论已关闭.