title: Serial Port Receive Thread Not Behaving as Expected - C++
body: <p>My application uses a separate thread for handling received serial data asynchronously.  The PC gets into the receive-handler as expected, but from there things go weird.</p>
  
  <p>This is my thread function:</p>
  
  <pre><code>// Create event for OVERLAPPED structure.
  s_ov.hEvent = ::CreateEvent(
      NULL,                           // No security
      TRUE,                           // Create a manual-reset event object
      FALSE,                          // Initial state is non-signaled
      NULL                            // No name specified
      );
  
  // Load event handles.
  pHandles[0] = s_hSerialPortRxThreadExitEvent;
  
  while ( bContinue )
  {
      if ( !::WaitCommEvent( s_hSerialPort, &amp;dwEventMask, &amp;s_ov ) )
      {
          if ( ::GetLastError() != ERROR_IO_PENDING )
          {
              TRACE(_T("SerialPortRxThreadFn : Call to WaitCommEvent failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
              return ::GetLastError();
          }
      }
  
      pHandles[1] = s_ov.hEvent;
  
      dwObjectWaitState = ::WaitForMultipleObjects( 2, pHandles, FALSE, INFINITE );
  
      switch ( dwObjectWaitState )
      {
      case WAIT_ABANDONED:
          TRACE(_T("SerialPortRxThreadFn : Owner thread terminated prematurely.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ERROR_ARENA_TRASHED, __WFILE__, __LINE__);
          return ERROR_ARENA_TRASHED;
          break;
  
      case WAIT_TIMEOUT:
          TRACE(_T("SerialPortRxThreadFn : The timeout is set to INFINITE; there should be no timeout.  State is nonsignaled.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), WAIT_TIMEOUT, __WFILE__, __LINE__);
          return WAIT_TIMEOUT;
          break;
  
      case WAIT_FAILED:
          TRACE(_T("SerialPortRxThreadFn : Call to WaitCommEvent failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
          return ::GetLastError();
          break;
  
      case WAIT_OBJECT_0:             // thread exit event signalled
          bContinue = FALSE;
  
          if ( !::ResetEvent( pHandles[0] ) )
          {
              TRACE(_T("SerialPortRxThreadFn  : Failed to reset the serial port thread exit event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
              return ::GetLastError();
          }
          break;
  
      case WAIT_OBJECT_0 + 1:         // OVERLAPPED structure event signalled
          // Read data from serial port.
          if ( !::ReadFile( s_hSerialPort, pBuf, RX_BUF_SIZE, &amp;dwWritten, &amp;s_ov ) ) // &lt;- Set breakpoint here
          {
              TRACE(_T("SerialPortRxThreadFn : Call to ReadFile filed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
              return ::GetLastError();
          }
  
          // Discontinue thread operation if there are no more bytes in the serial port receive buffer.
          if ( dwWritten == 0 ) // &lt;- Or, set breakpoint here
          {
              bContinue = FALSE;
          }
          // Copy the received bytes to the thread-safe buffer.
          else if ( !s_pobjRxRingBuffer-&gt;Add( pBuf, dwWritten, TRUE ) )
          {
              TRACE(_T("SerialPortRxThreadFn : Failed to add bytes to ring buffer.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ERROR_INSUFFICIENT_BUFFER, __WFILE__, __LINE__);
              return ERROR_INSUFFICIENT_BUFFER;
          }
          else if ( s_SpCallbackFn != NULL )
          {
              // Notify application of received data.
              if ( (dwRetVal = s_SpCallbackFn( s_pobjRxRingBuffer-&gt;ItemsInBuffer() )) != ERROR_SUCCESS )
              {
                  TRACE(_T("SerialPortRxThreadFn : Serial port callback function failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwRetVal, __WFILE__, __LINE__);
                  return dwRetVal;
              }
          }
  
          if ( !::ResetEvent( pHandles[1] ) )
          {
              TRACE(_T("SerialPortRxThreadFn : Failed to reset the OVERLAPPED structure event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
              return ::GetLastError();
          }
          break;
  
      default:
          // Do nothing.
          break;
      }
  }
  
  ::CloseHandle( s_ov.hEvent );
  
  return ERROR_SUCCESS;
  </code></pre>
  
  <p>If I set my breakpoint on the line calling <code>ReadFile</code> everything works as I expect, and the PC gets into the callback function.  However, if I set my breakpoint at the next line, where <code>dwWritten</code> is evaluated for zero, it is zero, the expression evaluates as TRUE, and the loop exits; the PC never gets to the callback.  What am I doing wrong?  Thanks.</p>