zoukankan      html  css  js  c++  java
  • Delphi多线程编程之五不同类线程读写全局变量阻塞和锁定

    (调试环境: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.Acquire或TCriticalSection.Enter来阻塞。

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

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

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

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

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

    2、建立TMultiReadExclusiveWriteSynchronizer.Create。

    3、每个线程在读一个全局变量前要先调用该类的BeginRead()来检查是否有其他线程在写这个变量。如果有,就等待,直到其他线程不再写这个变量才返回。当读好后,调用EndRead()来结束。

    如果一个线程要写这个变量,必须先调用BeginWrite()来检查当前是否有其他现成在写这个变量并且所有线程是否都调用了EndRead()。只要有一个线程正在写这个变量,或者有一个线程还没有调用EndRead(),BeginWrite()将一直等待。当线程写完以后,必须及时地调用EndWrite(),一边其他线程可以读写这个全局变量。

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

  • 相关阅读:
    数据库的未来:ORM+LINQ+RX
    工具论-科学是实用工具
    事务、锁与原子性
    ORM-面向对象&关系数据库
    swift Class的内存布局
    使用phpexcel导出到xls文件的时候出现乱码解决
    苹果CMS
    js网页如何获取手机屏幕宽度
    常用正则说明
    php中的线程、进程和并发区别
  • 原文地址:https://www.cnblogs.com/94YY/p/2199346.html
Copyright © 2011-2022 走看看