Board index » delphi » Serial communication / thread problem

Serial communication / thread problem

Hello all,

I'm using a component TComPort for communication with external hardware. The
component contains a thread object which calls events, triggered by the
status of the comport. This is also the only reason why this thread is
needed. This is what happens:

1) In TComport.Open a file handle is created that makes reading from and
writing to the comport possible.
2) Furthermore, the thread object is created. In the thread object a
stopevent is created that makes exiting the execute procedure  possible.
3) Application is closed, TComPort.Close is executed. ComThread is Freed, so
StopEvent is set and execute wil be terminated.
4) Then, in TComport.Close, ComHandle is closed. This statement creates an
exception $0E every now and then, with the familiar blue screen. Why does
this happen? Only when I set the priority to tpTimeCritical or when I don't
create the thread object, I don't get a blue screen.

What could be the reason for this?

Thanks in advance for the help!

Roy

***** TComPort object ******

procedure TComPort.Open;
begin
  ComHandle := CreateFile(PChar(ComString), GENERIC_READ or GENERIC_WRITE,
    0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  ComThread := TComThread.Create;
end;

procedure TComPort.Close;
begin
  ComThread.Free;
  if ComHandle <> INVALID_HANDLE_VALUE then
    CloseHandle(ComHandle);
end;

***** TComThread object *****

procedure TComThread.Execute;
var
  EventHandles: Array[0..1] of THandle;
  Overlapped: TOverlapped;
  dwSignaled, BytesTrans: DWORD;
begin
  FillChar(Overlapped, SizeOf(Overlapped), 0);
  Overlapped.hEvent := CreateEvent(nil, True, True, nil);
  EventHandles[0] := StopEvent;
  EventHandles[1] := Overlapped.hEvent;
  repeat
    WaitCommEvent(Owner.ComHandle, Mask, @Overlapped);
    dwSignaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);
    case dwSignaled of
      WAIT_OBJECT_0:
        Break;
      WAIT_OBJECT_0 + 1:
        if GetOverlappedResult(Owner.ComHandle, Overlapped,
          BytesTrans, False) then Synchronize(DoEvents);
      else Break;
    end;
  until False;
  Owner.PurgeIn;
  Owner.PurgeOut;
  CloseHandle(Overlapped.hEvent);
  CloseHandle(StopEvent);
end;

constructor TComThread.Create(AOwner: TComPort);
begin
  inherited Create(True);
  StopEvent := CreateEvent(nil, True, False, nil);
  Owner := AOwner;
  Priority := tpTimeCritical;
  Resume;
end;

destructor TComThread.Destroy;
begin
  SetEvent(StopEvent);
  inherited Destroy;
end;

 

Re:Serial communication / thread problem


Hi !

I have seen that when you free a thread that is waiting at some
WaitFor... semaphore or event is "slipping through" as it is freed. I
have found it safest to suspend the thread before it is freed. In some
cases I have let a tpTimeCritical thread manage freeing of other
threads.

--
Bjoerge Saether
Consultant / Developer
Asker, Norway
bsaether.removet...@online.no (remove the obvious)

Roy Rutten skrev i meldingen <82r93c$164...@reader3.wxs.nl>...

Quote
>Hello all,

>I'm using a component TComPort for communication with external
hardware. The
>component contains a thread object which calls events, triggered by the
>status of the comport. This is also the only reason why this thread is
>needed. This is what happens:

>1) In TComport.Open a file handle is created that makes reading from
and
>writing to the comport possible.
>2) Furthermore, the thread object is created. In the thread object a
>stopevent is created that makes exiting the execute procedure
possible.
>3) Application is closed, TComPort.Close is executed. ComThread is
Freed, so
>StopEvent is set and execute wil be terminated.
>4) Then, in TComport.Close, ComHandle is closed. This statement creates
an
>exception $0E every now and then, with the familiar blue screen. Why
does
>this happen? Only when I set the priority to tpTimeCritical or when I
don't
>create the thread object, I don't get a blue screen.

>What could be the reason for this?

>Thanks in advance for the help!

>Roy

>***** TComPort object ******

>procedure TComPort.Open;
>begin
>  ComHandle := CreateFile(PChar(ComString), GENERIC_READ or
GENERIC_WRITE,
>    0, nil, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
>  ComThread := TComThread.Create;
>end;

>procedure TComPort.Close;
>begin
>  ComThread.Free;
>  if ComHandle <> INVALID_HANDLE_VALUE then
>    CloseHandle(ComHandle);
>end;

>***** TComThread object *****

>procedure TComThread.Execute;
>var
>  EventHandles: Array[0..1] of THandle;
>  Overlapped: TOverlapped;
>  dwSignaled, BytesTrans: DWORD;
>begin
>  FillChar(Overlapped, SizeOf(Overlapped), 0);
>  Overlapped.hEvent := CreateEvent(nil, True, True, nil);
>  EventHandles[0] := StopEvent;
>  EventHandles[1] := Overlapped.hEvent;
>  repeat
>    WaitCommEvent(Owner.ComHandle, Mask, @Overlapped);
>    dwSignaled := WaitForMultipleObjects(2, @EventHandles, False,
INFINITE);
>    case dwSignaled of
>      WAIT_OBJECT_0:
>        Break;
>      WAIT_OBJECT_0 + 1:
>        if GetOverlappedResult(Owner.ComHandle, Overlapped,
>          BytesTrans, False) then Synchronize(DoEvents);
>      else Break;
>    end;
>  until False;
>  Owner.PurgeIn;
>  Owner.PurgeOut;
>  CloseHandle(Overlapped.hEvent);
>  CloseHandle(StopEvent);
>end;

>constructor TComThread.Create(AOwner: TComPort);
>begin
>  inherited Create(True);
>  StopEvent := CreateEvent(nil, True, False, nil);
>  Owner := AOwner;
>  Priority := tpTimeCritical;
>  Resume;
>end;

>destructor TComThread.Destroy;
>begin
>  SetEvent(StopEvent);
>  inherited Destroy;
>end;

Re:Serial communication / thread problem


I don't think I even need to read the code:  it's a timing problem.
That's why the exception is on-again, off-again.  In step #3 you say
that the port is closed, and the thread is freed. Then in step #4...
etc.  Well, the events as you describe them depend upon the thread,
having been freed, to be dispatched one-last-time at a particular time,
interleaved with the other cleanup events.

Code that wants to stop a thread has to -wait- for the thread to
terminate, before proceeding with any freeing or other cleanup-actions.
Otherwise a timing problem is created like the one you see here.  The
thread, although it has been killed, will still get dispatched to do its
cleanup routine ... and this can occur at any time relative to the
execution of your cleanup code.  When it's out-of-whack, AND the
virtual-memory page that contained the object you just freed happened to
have been invalidated (there wasn't something else in-use on that page),
an exception $0E occurs.

Quote
>Roy Rutten wrote:

> Hello all,

> I'm using a component TComPort for communication with external hardware. The
> component contains a thread object which calls events, triggered by the
> status of the comport. This is also the only reason why this thread is
> needed. This is what happens:

[...]
> 3) Application is closed, TComPort.Close is executed. ComThread is Freed, so
> StopEvent is set and execute wil be terminated.
> 4) Then, in TComport.Close, ComHandle is closed. This statement creates an
> exception $0E every now and then, with the familiar blue screen.

----------------------------------------------------------------------
Sundial Services :: Scottsdale, AZ (USA) :: (480) 946-8259
mailto:i...@sundialservices.com  (PGP public key available.)
Quote
> High-speed, script-driven, table repair/support for Paradox/BDE...
> ChimneySweep{tm}:  "Click click, it's fixed!" {tm}
> http://www.sundialservices.com/cs3web.htm

Other Threads