我写了个用WaitForMultipleObjects同步线程的例子,窗体上有三个memo,有一个mutex数组变量,分别对应一个memo,主线程里创建调度线程,在调度线程里通过WaitForMultipleObjects得到当前空闲的mutex,对应的我就知道了哪个memo是空闲的,然后创建一个工作线程,工作线程里向对应的memo写数据,
现在的问题是,WaitForMultipleObjects返回后,始终得到的是0,按理WaitForMultipleObjects返回后,mutex数组的第一个元素就处于未激发状态了,如果再调用WaitForMultipleObjects就不应返回0了

下面是代码,请帮我看看问题在哪unit Unit1;interfaceuses
  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.

解决方案 »

  1.   

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

  2.   

    楼上正解~~~~因为LZ的GetIdleMemo函数一直是由线程TDispThd来调用的,所以一直都可重入WaitForMultiOjbect,将GetIdleMemo这个函数放在TWorker.Execute执行,即可;如下所示,我改了一下代码,是可以的.unit Unit1;interfaceuses
      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.