线程同步实例

来源:互联网 发布:把.js文件压缩.min.js 编辑:程序博客网 时间:2024/05/21 11:04
通过事件同步主线程与从线程的实例
▲ 实例定义了一个主类:        Tlistfile。该类主要是根具recmail变量,把它存入一个文件或从一个文件中读取出来。在该类上可实现:两个或多个应用程序之间通过文件进行异步问答式通讯。所谓问答式异步通讯是:一个程序发问,只有等到其他程序回答后才能继续发问。在一个时刻只能有一个程序使用该通讯文件,并且发送信息时必须进快完成。
▲该类约定了存取所用的文件是同一个文件且存在。
▲存recmail变量用savereclist方法,读recmail用loadreclist方法。
●savereclist方法实现:用TsaveThread线程实现。
当外界调用savereclist方法时,该方法首先创建一个TsaveThread线程,然后运行它,由它完成存取文件的操作,接着挂起主线程,等等TsaveThread线程执行完毕,TsaveThread线程执行完毕唤醒主线程。为了防止多个TsaveThread线程之间的干扰,在TsaveThread线程内用了临界区同步变量进行线程同步。
●loadreclist方法实现:用TloadThread线程实现。
当外界调用loadreclist方法时,该方法首先创建一个TloadThread线程,然后运行它,由它完成读取文件的操作,接着挂起主线程,等等TloadThread线程执行完毕,TloadThread线程执行完毕唤醒主线程。为了防止多个TloadThread线程之间的干扰,在TloadThread线程内用了临界区同步变量进行线程同步。

unit listfile;
interface
uses Classes,SysUtils,StrUtils,ExtCtrls,SyncObjs,Dialogs,windows;
type
  precmail =^trecmail;
  Trecmail =record
    subject :string[150];//异步通信内容
    recDate :tdatetime;//通信时时间
    askBL,answerSBL,answerFBL :boolean;//定义了文件的问、开始回答、回答完毕标识。
  end;

  TlistFile=class //主类
  public
    recmail:Trecmail;
    constructor  create(filename:string);//创建时获得通讯文件名
    procedure savereclist();
    procedure loadreclist();
    destructor destroy;
  end;

  TLoadThread=class(TThread) //读取线程
  protected
    Procedure Execute;override;
  end;

  TSaveThread=class(TThread)式//存取线程
  protected
    Procedure Execute;override;
  end;

  function IsFileInUse(fName : string ) : boolean;//文件在用检测函数

var
   srecmail:Trecmail;//读存线程与主线程的recmail通信所用的变量
   sfilename:string;// 异步通讯文件变量
   Critical1,Critical2:TCriticalSection;//分别是读线程、存线程同步所用的临界变量
   sevent1,sevent2:tsimpleEvent; /分别是读线程与主线程、存线程与主线程同步所用的同步事件变量
implementation
function IsFileInUse(fName : string ) : boolean;
var
  HFileRes : Tfilestream;
begin
  Result := false;
  if not FileExists(fName) then
    exit;
  try
    hfileres:=Tfilestream.create(fname,fmShareExclusive);
    result:=false;
  except
    result:=true;
  end;
  try
    hfileres.Free;
  except
  end;
end;

procedure TLoadThread.Execute;//读线程的执行代在码
var
  fl:file of trecmail;  loadBL:boolean;
begin
  Critical1.Enter ;//临界区同步开始
  loadBL:=true;
  while true do  //循环的原因是当通信文件还在使用是就不停的等待,直到可以使用该文件
  begin
    if  not (IsFileInUse(sfilename))  then
    begin
      if not loadBL  then
      begin
         Critical1.Leave ;
         sevent1.SetEvent ;//唤醒挂起的主线程
         exit;
      end else
      begin
        AssignFile(fl,sfilename);
        reset(fl);
        read(fl,srecmail);
        closefile(fl);
        loadBL:=false;
      end;
    end;
  end;
  Critical1.Leave ; //临界区同步结束
end;

procedure TSaveThread.Execute;// 存线程的执行代在码
var
  fl:file of trecmail;  saveBL:boolean;
begin
  Critical2.Enter ; //临界区同步开始
  saveBL:=TRUE;
  while true do  //循环的原因是当通信文件还在使用是就不停的等待,直到可以使用该文件
  begin
    if  (not IsFileInUse(sfilename)) then
    begin
      if not saveBL  then
      begin
        Critical2.Leave ;
        sevent2.SetEvent ; //唤醒挂起的主线程
        exit;
      end else
      begin
        AssignFile(fl,sfilename);
        rewrite(fl);
        write(fl,srecmail);
        closefile(fl);
        saveBL:=false;
      end;
    end;
  end;
  Critical2.Leave ; //临界区同步结束
end;

constructor TlistFile.create(filename:string);
begin
  sfilename:=  filename;//得到同步文件名
  Critical1:= TCriticalSection.Create ;//创建读临界区同步对象
  Critical2:= TCriticalSection.Create ; //创建存临界区同步对象
end;

procedure TlistFile.savereclist();//存文件操作
var
   saveThread:TSaveThread;
begin
  srecmail:=recmail ;//得存文件时,存线程要用到的要存通讯数据
  sevent2:=TSimpleEvent.Create ;//创建与存线程同步所用的同步事件对象
  sevent2.ResetEvent;//此处决定了该事件操纵的线程是主线程,因为第一次调用它的是主线程。
                  //用了该方法后,再用WaitFor(INFINITE);时,主线程将被挂起
  saveThread:= TSaveThread.create(true);//创建存线程对象,创建后不立即执行。
  saveThread.FreeOnTerminate :=true;//此处是当存线程执行完毕后自动灭亡,并释放资源。
  saveThread.Resume;//唤醒存线程让之运行,以执行存文件任务
  sevent2.WaitFor(INFINITE);//主线程被挂起,直到存线程执行完毕唤醒它
  sevent1.Release ;//释放sevent2所用到的资源
end;

procedure TlistFile.loadreclist();//读文件操作
var
   LoadThread:TLoadThread;
begin
  sevent1:=TSimpleEvent.Create ;// 创建与读线程同步所用的同步事件对象
  sevent1.ResetEvent; //此处决定了该事件操纵的线程是主线程,因为第一次调用它的是主线程。
                   //用了该方法后,再用WaitFor(INFINITE);时,主线程将被挂起
  LoadThread:= TLoadThread.create(true); //创建读线程对象,创建后不立即执行。
  LoadThread.FreeOnTerminate :=true;
  loadThread.Resume ; //唤醒读线程让之运行,以执行读文件任务
  sevent1.WaitFor(INFINITE); //此处是当读线程执行完毕后自动灭亡,并释放资源。
  recmail:=srecmail ; //主线程得到读线程读到的通讯数据,以使文件通过recmail访问
  sevent1.Release ;//释放sevent1所用到的资源
end;

destructor TlistFile.destroy;
begin
  inherited destroy;
  Critical1.Destroy   ;
  Critical2.Destroy  ;
end;

end.
 
原创粉丝点击