在主窗口中含有两个公共变量 pbArray 、pb,两个线程同时写入改两个变量的内容。 未防止同步错误,加入了   CS : TCriticalSection ,但不清楚下面的定义及使用方法是否有错?
 另外:如果没有错误的话,在每个线程内部定义的局部  CS : TCriticalSection在进行同步操作时如何确定另外线程的  CS : TCriticalSection对象能够正确被使用,而不是同时都使用?
线程1procedure TH1.Execute;
var
 n : integer;
 CS : TCriticalSection;
begin
  { Place thread code here }
  CS := TCriticalSection.Create;
  form1.Label1.Caption := IntToStr(self.ThreadID);
  while not Self.Terminated do
   begin
    sleep(20);
    for n := 0 to high(Form1.pbArray) do
     begin        form1.ProgressBar1.Position := n;        CS.Acquire;
        try
            form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
            form1.pb         := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
        finally
            CS.Release;
        end;
     end;    //CRITICAL_SECTION
   end;end;
线程2procedure TH2.Execute;
var
 n : integer;
 CS : TCriticalSection;
begin  { Place thread code here }
  CS := TCriticalSection.Create;
  form1.Label2.Caption := IntToStr(self.ThreadID);
  while not Self.Terminated do
   begin
    sleep(20);
    for n := 0 to high(Form1.pbArray) do
     begin        form1.ProgressBar2.Position := n;        CS.Acquire;
        try
            form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
            form1.pb         := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
        finally
        CS.Release;
        end;
     end;   end;end;

解决方案 »

  1.   

    放在哪我管不着,我只能告诉你
    一个TCriticalSection表示一个临界区,你就看成一张门,门里面只能有一个线程进去,如果里面有线程,其他线程就进不去,知道其他线程出来。
    你如果创建了两个TCriticalSection,那就表示有两张门,如果线程要同步访问一个对象或内存,你应该只给它们搞一张门。
      

  2.   

    随后我又写了如下的解决办法,请问高手哪种比较可取,需要注意些什么?主窗体代码:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ComCtrls, unit2,unit3,SyncObjs;type
      TForm1 = class(TForm)
        ProgressBar1: TProgressBar;
        ProgressBar2: TProgressBar;
        Button1: TButton;
        Label1: TLabel;
        Label2: TLabel;
        procedure Button1Click(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private declarations }    t1 : TH1;
        t2 : TH2;
      public
        { Public declarations }
        pbArray : array[0..2000] of string;
        pb : string;
        //CS : TCriticalSection;  end;var
      Form1: TForm1;
         Lock : TRTLCriticalSection;
    implementation{$R *.dfm} 
    procedure TForm1.Button1Click(Sender: TObject);
    begin t1 := TH1.Create(false); t2 := TH2.Create(false);end;procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
     t1.Terminate;
     t2.Terminate; FreeAndNil(t1);
     FreeAndNil(t2);
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
    InitializeCriticalSection(Lock);
    end;procedure TForm1.FormDestroy(Sender: TObject);
    begin
    DeleteCriticalSection(Lock);end;end.
    线程1代码:unit Unit2;interfaceuses
      Classes,SysUtils,SyncObjs,Windows;type
      TH1 = class(TThread)
      private
        { Private declarations }
      protected
        procedure Execute; override;
      end;implementation{ Important: Methods and properties of objects in visual components can only be
      used in a method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TH1.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TH1 }
     uses
      unit1;
    procedure TH1.Execute;
    var
     n : integer;
     //CS : TCriticalSection;
    begin
      { Place thread code here }
      //CS := TCriticalSection.Create;
      form1.Label1.Caption := IntToStr(self.ThreadID);
      while not Self.Terminated do
       begin
        sleep(20);
        for n := 0 to high(Form1.pbArray) do
         begin        form1.ProgressBar1.Position := n;        //CS.Acquire;
            EnterCriticalSection(lock);        try
                form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
                form1.pb         := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
            finally
                //CS.Release;
            LeaveCriticalSection(lock);
            end;
         end;    //CRITICAL_SECTION
       end;end;end.{var criticalsection: TCriticalsection;
    创建:criticalsection := TCriticalsection.create;
    使用:
    criticalsection.enter;
    try
    ...
    finally
    criticalsection.leave;
    end;
    }线程2代码unit Unit3;interfaceuses
      Classes,SysUtils,SyncObjs,Windows;type
      TH2 = class(TThread)
      private
        { Private declarations }
      protected
        procedure Execute; override;
      end;implementation{ Important: Methods and properties of objects in visual components can only be
      used in a method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TH2.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TH2 }
    uses
     unit1;
    procedure TH2.Execute;
    var
     n : integer;
     //CS : TCriticalSection;
    begin  { Place thread code here }
      //CS := TCriticalSection.Create;
      form1.Label2.Caption := IntToStr(self.ThreadID);
      while not Self.Terminated do
       begin
        sleep(20);
        for n := 0 to high(Form1.pbArray) do
         begin        form1.ProgressBar2.Position := n;
            EnterCriticalSection(lock);        try
                form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
                form1.pb         := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
            finally
                //CS.Release;
            LeaveCriticalSection(lock);
            end;
            {
            CS.Acquire;
            try
                form1.pbArray[n] := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
                form1.pb         := FormatDateTime('yyyy-mm-dd hh:nn:ss:zzz',now);
            finally
            CS.Release;
            end;
            }
         end;   end;end;end.
      

  3.   

    一、临界区
    所谓临界区,就是一次只能由一个线程来执行的一段代码。如果把初始化数组的代码放在临界区内,另一个线程在第一个线程处理完之前是不会被执行的。
    使用临界区的步骤:
    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);后,会产生错误。=================
    主要目的是把读写全局数据的语句放在临界区去,这样在一个线程读写完成全,另一个线程会等待
      

  4.   

    要区分读写的比较复杂,用用TMultiReadExclusiveWriteSynchronizer类来阻塞,可以写成TMREWSync这样随便你,你想阻塞读或者写都成。