Serial communication options

Giganews Newsgroups
Subject: Serial communication options
Posted by:  Enquiring Mind (Enquiring.Mind@nospam.btopenworld.com)
Date: Tue, 10 Jun 2008

Hi,

I have had a quick look at the SDK help files on the subject of serial
communications, and needless to say I am still rather confused, because as
usual there seem to be a multiplicity of ways of doing the same thing with
the possibility of unwanted interaction between them. The epithet
'unnecessarily complex' springs to mind! Can any synchronization expert help
me understand the pros and cons of the various options available for serial
communication using Windows API functions?

It seems to me that the options could include:

1. Create a file without the Overlapped flag, and make a synchronous call of
ReadFile in the loop of a secondary thread. The thread is blocked until the
ReadFile function returns, then processes the data read.

procedure TThread1.Execute;
begin
  repeat
    ReadFile(...);  {Synchronous call; thread blocked}
    ProcessDataRead(...);
  until Terminated;
end;

2. As per 1, except that file is created with the Overlapped flag, and the
WaitForSingleObjectEx function is called immediately after ReadFile. The
ReadFile function returns immediately, but the thread remains blocked during
the execution of WaitForSingleObjectEx.

procedure TThread1.Execute;
begin
  repeat
    ReadFile(...);  {Asynchronous call}
    WaitForSingleObjectEx(...);  {thread blocked}
    ProcessDataRead(...);
  until Terminated;
end;

Although the read operation has been called asynchronously from the calling
thread, the calling thread  still has to wait for the read operation to
complete.

3. As per 2, except that the ReadFileEx function instead of the ReadFile
function is used to read the data asynchronously, a completion routine is
passed to this function, and WaitForSingleObjectEx is not used:

  procedure StartRead(..)
  begin
    ReadFileEx(...);  {Asynchronous call which triggers recursive
iteration}
  end;

  procedure EndRead(...);  {called from completion routine}
  begin
      ProcessDataRead(..);
      if not FTerminated then
        StartRead(..);  {Recursive call}
  end;

  procedure TMainForm.ButtonStartClick(..);
  begin
    FTerminated:= False;
    StartRead;
  end;

EndRead is called from the completion routine. Here iteration is achieved by
recursion. Everything takes place as event handlers in the main thread.
There is no blockage of any application thread.

4. As per 3, except that ReadFileEx is called from within a thread loop
which also includes a call to WaitForSingleObjectEx. Since the
ProcessDataRead is now in the thread loop, the completion routine is not
needed and may be set to nil:

procedure TThread1.Execute;
begin
  repeat
    ReadFileEx(...);  {Asynchronous call}
    WaitForSingleObjectEx(...);  {thread blocked}
    ProcessDataRead(...);
  until Terminated;
end;

In this case there seems to be a lot of added complication, but little
benefit in performance.

My questions are:

1. Is option 2 significantly more efficient than option 1? I understand that
the WaitForSingleObjectEx call puts the calling thread to sleep, thereby
saving CPU time. Does this not  happen if WaitForSingleObjectEx is not
called?

2. Is there any real benefit in using ReadFileEx instead of ReadFile? If we
call WaitForSingleObjectEx then there is no real need for a completion
routine.

3. If we use a completion routine, then we do not need to call the
asynchronous read in a separate thread. But am I right in thinking that the
completion routine has to be a global procedure - methods of objects not
being acceptable?

4. Instead of getting the completion routine to call ProcessDataRead(...),
could we get it to simply post a message to the application so that an
message handler of the main form gets to call ProcessDataRead(...)?

TIA,

EM

Replies