delphi2007 教程

delphi2007 教程

首页 新随笔 联系 聚合 管理
  1013 Posts :: 0 Stories :: 28 Comments :: 0 Trackbacks
为什么WaitForMultipleObjects返回后,对应的handle仍处于激发状态? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiAPI/html/delphi_20061107172543284.html
我写了个用WaitForMultipleObjects同步线程的例子,窗体上有三个memo,有一个mutex数组变量,分别对应一个memo,主线程里创建调度线程,在调度线程里通过WaitForMultipleObjects得到当前空闲的mutex,对应的我就知道了哪个memo是空闲的,然后创建一个工作线程,工作线程里向对应的memo写数据,  
  现在的问题是,WaitForMultipleObjects返回后,始终得到的是0,按理WaitForMultipleObjects返回后,mutex数组的第一个元素就处于未激发状态了,如果再调用WaitForMultipleObjects就不应返回0了  
  。  
  下面是代码,请帮我看看问题在哪  
   
  unit   Unit1;  
   
  interface  
   
  uses  
      Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,  
      Dialogs,   StdCtrls;  
   
  type  
      TForm1   =   class(TForm)  
          Button1:   TButton;  
          Memo1:   TMemo;  
          Memo2:   TMemo;  
          Memo3:   TMemo;  
          procedure   FormCreate(Sender:   TObject);  
          procedure   FormDestroy(Sender:   TObject);  
          procedure   Button1Click(Sender:   TObject);  
      private  
          {   Private   declarations   }  
      public  
          {   Public   declarations   }  
      end;  
   
      TDispThd   =   class(TThread)  
      private  
   
      protected  
          procedure   Execute;   override;  
      public  
          constructor   Create(Mone:   TMemo;   Mtwo:   TMemo;   Mthree:   TMemo);  
      end;  
      TWorker   =   class(TThread)  
      private  
          FMemo:   TMemo;  
          FTID:   integer;  
          FIndex:   integer;  
      protected  
          procedure   Execute;   override;  
          procedure   UpdateMemo;  
      public  
          constructor   Create(index,   id:   integer;   memo:   TMemo);  
      end;  
   
  var  
      Form1:   TForm1;  
      ConnMutexUse:   array[0..2]   of   THandle;  
      MemoArr:   array[0..2]   of   TMemo;  
   
  procedure   GetIdleMemo(var   id:   integer);  
   
  implementation  
   
  {$R   *.dfm}  
   
  procedure   GetIdleMemo(var   id:   integer);  
  var  
      WaitRes:   integer;  
  begin  
      WaitRes   :=   WaitForMultipleObjects(3,   @ConnMutexUse,   False,   INFINITE);  
      id   :=   WaitRes   -   WAIT_OBJECT_0;  
    //   waitres   :=   WaitForSingleObject(ConnMutexUse[ID],   10);  
    //   if   waitres   =   WAIT_OBJECT_0   then  
    //       raise   Exception.Create('bad,i   catch   it');  
      if   (id   <   0)   or   (id   >   2)   then  
          raise   Exception.Create('GetIdle错误');  
  end;  
   
  constructor   TDispThd.Create(Mone:   TMemo;   Mtwo:   TMemo;   Mthree:   TMemo);  
  begin  
      MemoArr[0]   :=   Mone;  
      MemoArr[1]   :=   Mtwo;  
      MemoArr[2]   :=   Mthree;  
      inherited   Create(false);  
  end;  
   
  procedure   TDispThd.Execute;  
  var  
      id,   i,   WaitRes:   integer;  
  begin  
      FreeOnTerminate   :=   true;  
      i   :=   0;  
      while   true   do  
      begin  
          GetIdleMemo(id);  
      //     WaitRes   :=   WaitForMultipleObjects(3,   @ConnMutexUse,   False,   INFINITE);  
      //     id   :=   WaitRes   -   WAIT_OBJECT_0;  
      //     waitres   :=   WaitForSingleObject(ConnMutexUse[ID],   10);  
      //     if   waitres   =   WAIT_OBJECT_0   then  
      //         raise   Exception.Create('bad,i   catch   it');  
      //     if   (id   <   0)   or   (id   >   2)   then  
      //         raise   Exception.Create('GetIdle错误');  
   
          TWorker.Create(i,   id,   MemoArr[id]);  
          sleep(2000);  
          Inc(i);  
      end;  
  end;  
   
  procedure   TForm1.FormCreate(Sender:   TObject);  
  var  
      i:   integer;  
  begin  
      for   i   :=   0   to   2   do  
          ConnMutexUse[i]   :=   CreateMutex(nil,   false,   nil);  
  end;  
   
  procedure   TForm1.FormDestroy(Sender:   TObject);  
  var  
      i:   integer;  
  begin  
      for   i   :=   0   to   2   do  
          CloseHandle(ConnMutexUse[i]);  
  end;  
   
  constructor   TWorker.Create(index,   id:   integer;   memo:   TMemo);  
  begin  
      FMemo   :=   memo;  
      FTID   :=   id;  
      FIndex   :=   index;  
      FreeOnTerminate   :=   true;  
      inherited   Create(false);  
  end;  
   
  procedure   TWorker.Execute;  
  var  
      waitres:   integer;  
  begin  
      try  
          Synchronize(UpdateMemo);  
  //         waitres   :=   WaitForSingleObject(ConnMutexUse[FTID],   10);  
  //         if   waitres   =   WAIT_OBJECT_0   then  
  //             raise   Exception.Create('bad,i   catch   it');  
          Sleep(50000);  
      finally  
          ReleaseMutex(ConnMutexUse[FTID]);  
      end;  
  end;  
   
  procedure   TWorker.UpdateMemo;  
  begin  
      FMemo.Lines.Add(IntToStr(FTID)   +   ':'   +   IntToStr(FIndex));  
  end;  
   
  procedure   TForm1.Button1Click(Sender:   TObject);  
  begin  
      TDispThd.Create(memo1,   Memo2,   Memo3);  
  end;  
   
  end.  
 

帮你顶

拥有mutex的线程是不会被锁定的,可以一直重入,它只会锁定其他线程。  
  通过WaitForSingleObject递增mutex内部计数,ReleaseMutex递减mutex内部计数。  
 

楼上正解~~~~  
   
  因为LZ的GetIdleMemo函数一直是由线程TDispThd来调用的,所以一直都可重入WaitForMultiOjbect,将GetIdleMemo这个函数放在TWorker.Execute执行,即可;  
   
  如下所示,我改了一下代码,是可以的.  
   
  unit   Unit1;  
   
  interface  
   
  uses  
      Windows,   Messages,   SysUtils,   Variants,   Classes,   Graphics,   Controls,   Forms,  
      Dialogs,   StdCtrls;  
   
  type  
      TForm1   =   class(TForm)  
          Memo1:   TMemo;  
          Memo2:   TMemo;  
          Memo3:   TMemo;  
          Button1:   TButton;  
          procedure   FormCreate(Sender:   TObject);  
          procedure   FormClose(Sender:   TObject;   var   Action:   TCloseAction);  
          procedure   Button1Click(Sender:   TObject);  
      private  
          {   Private   declarations   }  
      public  
          {   Public   declarations   }  
      end;  
   
      TDispThd   =   class(TThread)  
      private  
          ConnMutexUse:   array[0..2]   of   THandle;  
      protected  
          procedure   Execute;   override;  
      public  
   
          constructor   Create(Mone:   TMemo;   Mtwo:   TMemo;   Mthree:   TMemo);  
      end;  
   
      TWorker   =   class(TThread)  
      private  
          FMemo:   TMemo;  
          FTID:   integer;  
          FIndex:   integer;  
   
      protected  
          procedure   Execute;   override;  
          procedure   UpdateMemo;  
      public  
          constructor   Create(index,   id:   integer;   memo:   TMemo);overload;  
          constructor   Create(index:   integer);   overload;  
      end;  
  var  
      Form1:   TForm1;  
      ConnMutexUse:   array[0..2]   of   THandle;  
      MemoArr:   array[0..2]   of   TMemo;  
   
      procedure   GetIdleMemo(var   id:   integer);  
   
  implementation  
   
  {$R   *.dfm}  
   
  procedure   GetIdleMemo(var   id:   integer);  
  var  
      WaitRes:   integer;  
  begin  
      WaitRes   :=   WaitForMultipleObjects(3,   @ConnMutexUse,   FALSE,   INFINITE);  
      id   :=   WaitRes   -   WAIT_OBJECT_0;  
   
      if   (id   <   0)   or   (id   >   2)   then  
          raise   Exception.Create('GetIdle错误');  
  end;  
   
  {   TWorker   }  
   
  constructor   TWorker.Create(index,   id:   integer;   memo:   TMemo);  
  begin  
      FMemo   :=   memo;  
      FTID   :=   id;  
      FIndex   :=   index;  
      FreeOnTerminate   :=   true;  
      inherited   Create(false);  
  end;  
   
  constructor   TWorker.Create(index:   integer);   //增加一个构造函数  
  begin  
      FIndex   :=   index;  
      FreeOnTerminate   :=   true;  
      inherited   Create(false);  
  end;  
   
  procedure   TWorker.Execute;  
  var  
      waitres:   integer;  
  begin  
      GetIdleMemo(FTID);  
      FMemo   :=   MemoArr[FTID];  
      try  
          Synchronize(UpdateMemo);  
          Sleep(3500);   //时间调短,大于3*1000即可  
      finally  
          ReleaseMutex(ConnMutexUse[FTID]);  
      end;  
   
  end;  
   
  procedure   TWorker.UpdateMemo;  
  begin  
      FMemo.Lines.Add(IntToStr(FTID)   +   ':'   +   IntToStr(FIndex));  
  end;  
   
  {   TDispThd   }  
   
  constructor   TDispThd.Create(Mone,   Mtwo,   Mthree:   TMemo);  
  begin  
      MemoArr[0]   :=   Mone;  
      MemoArr[1]   :=   Mtwo;  
      MemoArr[2]   :=   Mthree;  
      inherited   Create(false);  
  end;  
   
  procedure   TDispThd.Execute;  
  var  
      id,   i,   WaitRes:   integer;  
  begin  
      FreeOnTerminate   :=   true;  
      i   :=   0;  
   
   
      while   true   do  
      begin  
          //GetIdleMemo(id);  
          //TWorker.Create(i,   id,   MemoArr[id]);  
           
          TWorker.Create(i);  
          sleep(1000);   //时间调短  
          Inc(i);  
      end;  
   
  end;  
   
  procedure   TForm1.FormCreate(Sender:   TObject);  
   
  var  
      i:   integer;  
  begin  
      for   i   :=   0   to   2   do  
          ConnMutexUse[i]   :=   CreateMutex(nil,   FALSE,   nil);  
  end;  
   
  procedure   TForm1.FormClose(Sender:   TObject;   var   Action:   TCloseAction);  
  var  
      i:   integer;  
  begin  
      for   i   :=   0   to   2   do  
          CloseHandle(ConnMutexUse[i]);  
  end;  
   
  procedure   TForm1.Button1Click(Sender:   TObject);  
  begin  
      TDispThd.Create(memo1,   Memo2,   Memo3);  
  end;  
   
  end.

谢谢各位的帮助

posted on 2009-04-08 09:12 delphi2007 阅读(513) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。