Alex  Tiger
Alex Tiger

Reputation: 387

Waitforsingleobject for event doesn't work

Main thread:

(Yes, I do stop main thread right now, I really need it right now for tests, this is test unit. I will do all this stuff in another thread during final stage.)

Code:

function TFreHolder.GetVersion: TFreHolderVersion;
Var
 Data   : TBArray;
 StrLen : Integer;
begin
 SetLength(Data, 0);

 FFrePro.SendCommand(PROTO_COMVERSION, Data);

 ResetEvent(FAsyncMutex);

 if (WaitForSingleObject(FAsyncMutex, PROTO_COMMANDTIMEOUT) = WAIT_TIMEOUT) Then
  Begin
   ShowMessage('Timeout');
   ResetEvent(FAsyncMutex);
   Exit;
  End;

Result.DType    := BytesToWord(FActivePackage.User.Parameters, 0);
Result.DVersion := BytesToWord(FActivePackage.User.Parameters, 2);
StrLen          := BytesToByte(FActivePackage.User.Parameters, 4);

if StrLen < 32
  then Result.DDesc    := BytesToString(FActivePackage.User.Parameters, 5)
  else Result.DDesc    := BytesToString(FActivePackage.User.Parameters, 4);

In the COM-port watching thread:

procedure TFreHolder.CommandSwitcher(Package: TFreProPackage);
...
Begin
     FActivePackage := Package;
     SetEvent(FAsyncMutex)
End;
...

I always see timeout message, but if I comment Waitforsingleobject I can see that bytes and packages are coming.

I have created Event in Constructor this way:

FAsyncMutex  := CreateEvent(Nil, True, False, 'FRE_EVENT');

What is my mistake? I need to wait the call of CommandSwitcher function before grabbing the results.

Thanks.

Upvotes: 0

Views: 2404

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598029

Assuming that another thread is receiving the response and then signaling FAsyncMutex when it has been received, then you need to call ResetEvent() before calling SendCommand(), not after. If the thread happens to receive the response before the sender is able to call ResetEvent() then it is forcing WaitForSingleObject() to timeout by clearing the condition it is waiting for.

Also, if WaitForSingleObject() times out waiting for an event to be signaled, do not call ResetEvent() since the event is not singaled.

Try this:

var
  Ret: DWORD;
...
ResetEvent(FAsyncMutex);
FFrePro.SendCommand(PROTO_COMVERSION, Data);

Ret := WaitForSingleObject(FAsyncMutex, PROTO_COMMANDTIMEOUT);
if Ret <> WAIT_OBJECT_0 then
begin
  if Ret = WAIT_TIMEOUT then
    ShowMessage('Timeout')
  else
    ShowMessage('Error');
  Exit;
end;

Upvotes: 4

kludg
kludg

Reputation: 27493

Well the code

ResetEvent(FAsyncMutex);
if (WaitForSingleObject(FAsyncMutex,...

is definitely a mistake because it ignores the async nature of threads.

Upvotes: 6

Related Questions