为什么WaitForMultipleObjects返回后,对应的handle仍处于激发状态? Delphi / Windows SDK/APIhttp://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.
谢谢各位的帮助