Yesky首页| 产品报价| 行情| 手机 | 数码 | 笔记本 | 台式机 | DIY硬件 | 外设 | 网络 | 数字家庭 | 评测 | 软件 | e时代 | 游戏 | 图片 | 壁纸 | 群乐 | 社区 | 博客 | 下载
软件频道>程序开发>JavaVBVCDelphiC/C++Web开发微软专栏移动数据库程序人生软件工程|产品中心下载什么是软件架构
您现在的位置: 天极网 > 开发频道 > 深入浅出Win32多线程程序设计之综合实例
全文

深入浅出Win32多线程程序设计之综合实例

2005-12-23 09:52 作者: 宋宝华 出处: 天极开发 责任编辑:方舟
  3.3.3核心函数:串口线程控制函数

  串口线程处理函数是整个类中最核心的部分,它主要完成两类工作:

  (1)利用WaitCommEvent函数对串口上发生的事件进行获取并根据事件的不同类型进行相应的处理;

  (2)利用WaitForMultipleObjects函数对串口相关的用户控制事件进行等待并做相应处理。

UINT CSerialPort::CommThread(LPVOID pParam)
{
 // Cast the void pointer passed to the thread back to
 // a pointer of CSerialPort class
 CSerialPort *port = (CSerialPort*)pParam;

 // Set the status variable in the dialog class to
 // TRUE to indicate the thread is running.
 port->m_bThreadAlive = TRUE;

 // Misc. variables
 DWORD BytesTransfered = 0;
 DWORD Event = 0;
 DWORD CommEvent = 0;
 DWORD dwError = 0;
 COMSTAT comstat;
 BOOL bResult = TRUE;

 // Clear comm buffers at startup
 if (port->m_hComm)
  // check if the port is opened
  PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

  // begin forever loop. This loop will run as long as the thread is alive.
  for (;;)
  {
   // Make a call to WaitCommEvent(). This call will return immediatly
   // because our port was created as an async port (FILE_FLAG_OVERLAPPED
   // and an m_OverlappedStructerlapped structure specified). This call will cause the
   // m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to
   // be placed in a non-signeled state if there are no bytes available to be read,
   // or to a signeled state if there are bytes available. If this event handle
   // is set to the non-signeled state, it will be set to signeled when a
   // character arrives at the port.

   // we do this for each port!

   bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);

   if (!bResult)
   {
    // If WaitCommEvent() returns FALSE, process the last error to determin
    // the reason..
    switch (dwError = GetLastError())
    {
     case ERROR_IO_PENDING:
     {
      // This is a normal return value if there are no bytes
      // to read at the port.
      // Do nothing and continue
      break;
     }
     case 87:
     {
      // Under Windows NT, this value is returned for some reason.
      // I have not investigated why, but it is also a valid reply
      // Also do nothing and continue.
      break;
     }
     default:
     {
      // All other error codes indicate a serious error has
      // occured. Process this error.
      port->ProcessErrorMessage("WaitCommEvent()");
      break;
     }
    }
   }
   else
   {
    // If WaitCommEvent() returns TRUE, check to be sure there are
    // actually bytes in the buffer to read.
    //
    // If you are reading more than one byte at a time from the buffer
    // (which this program does not do) you will have the situation occur
    // where the first byte to arrive will cause the WaitForMultipleObjects()
    // function to stop waiting. The WaitForMultipleObjects() function
    // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state
    // as it returns.
    //
    // If in the time between the reset of this event and the call to
    // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again
    // to the signeled state. When the call to ReadFile() occurs, it will
    // read all of the bytes from the buffer, and the program will
    // loop back around to WaitCommEvent().
    //
    // At this point you will be in the situation where m_OverlappedStruct.hEvent is set,
    // but there are no bytes available to read. If you proceed and call
    // ReadFile(), it will return immediatly due to the async port setup, but
    // GetOverlappedResults() will not return until the next character arrives.
    //
    // It is not desirable for the GetOverlappedResults() function to be in
    // this state. The thread shutdown event (event 0) and the WriteFile()
    // event (Event2) will not work if the thread is blocked by GetOverlappedResults().
    //
    // The solution to this is to check the buffer with a call to ClearCommError().
    // This call will reset the event handle, and if there are no bytes to read
    // we can loop back through WaitCommEvent() again, then proceed.
    // If there are really bytes to read, do nothing and proceed.

    bResult = ClearCommError(port->m_hComm, &dwError, &comstat);

    if (comstat.cbInQue == 0)
     continue;
   } // end if bResult

   // Main wait function. This function will normally block the thread
   // until one of nine events occur that require action.
   Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);

   switch (Event)
   {
    case 0:
    {
     // Shutdown event. This is event zero so it will be
     // the higest priority and be serviced first.

     port->m_bThreadAlive = FALSE;

     // Kill this thread. break is not needed, but makes me feel better.
     AfxEndThread(100);
     break;
    }
    case 1:
    // read event
    {
     GetCommMask(port->m_hComm, &CommEvent);
     if (CommEvent &EV_CTS)
      ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
     if (CommEvent &EV_RXFLAG)
      ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);
     if (CommEvent &EV_BREAK)
      ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);
     if (CommEvent &EV_ERR)
      ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
     if (CommEvent &EV_RING)
      ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED,(WPARAM)0, (LPARAM)port->m_nPortNr);
     if (CommEvent &EV_RXCHAR)
      // Receive character event from port.
      ReceiveChar(port, comstat);
    break;
   }
   case 2:
   // write event
   {
    // Write character event from port
    WriteChar(port);
    break;
   }
  } // end switch
 } // close forever loop
 return 0;
}

  下列三个函数用于对串口线程进行启动、挂起和恢复:

//
// start comm watching
//
BOOL CSerialPort::StartMonitoring()
{
 if (!(m_Thread = AfxBeginThread(CommThread, this)))
  return FALSE;
 TRACE("Thread started\n");
 return TRUE;
}

//
// Restart the comm thread
//
BOOL CSerialPort::RestartMonitoring()
{
 TRACE("Thread resumed\n");
 m_Thread->ResumeThread();
 return TRUE;
}

//
// Suspend the comm thread
//
BOOL CSerialPort::StopMonitoring()
{
 TRACE("Thread suspended\n");
 m_Thread->SuspendThread();
 return TRUE;
}

  3.3.4读写串口

  下面一组函数是用户对串口进行读写操作的接口:

//
// Write a character.
//
void CSerialPort::WriteChar(CSerialPort *port)
{
 BOOL bWrite = TRUE;
 BOOL bResult = TRUE;

 DWORD BytesSent = 0;

 ResetEvent(port->m_hWriteEvent);

 // Gain ownership of the critical section
 EnterCriticalSection(&port->m_csCommunicationSync);

 if (bWrite)
 {
  // Initailize variables
  port->m_ov.Offset = 0;
  port->m_ov.OffsetHigh = 0;

  // Clear buffer
  PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

  bResult = WriteFile(port->m_hComm, // Handle to COMM Port
    port->m_szWriteBuffer, // Pointer to message buffer in calling finction
    strlen((char*)port->m_szWriteBuffer), // Length of message to send
    &BytesSent, // Where to store the number of bytes sent
    &port->m_ov); // Overlapped structure

  // deal with any error codes
  if (!bResult)
  {
   DWORD dwError = GetLastError();
   switch (dwError)
   {
    case ERROR_IO_PENDING:
    {
     // continue to GetOverlappedResults()
     BytesSent = 0;
     bWrite = FALSE;
     break;
    }
    default:
    {
     // all other error codes
     port->ProcessErrorMessage("WriteFile()");
    }
   }
  }
  else
  {
   LeaveCriticalSection(&port->m_csCommunicationSync);
  }
 } // end if(bWrite)

 if (!bWrite)
 {
  bWrite = TRUE;

  bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port
   &port->m_ov, // Overlapped structure
   &BytesSent, // Stores number of bytes sent
  TRUE); // Wait flag

  LeaveCriticalSection(&port->m_csCommunicationSync);

  // deal with the error code
  if (!bResult)
  {
   port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");
  }
 } // end if (!bWrite)

 // Verify that the data size send equals what we tried to send
 if (BytesSent != strlen((char*)port->m_szWriteBuffer))
 {
  TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n",
  BytesSent, strlen((char*)port->m_szWriteBuffer));
 }
}

//
// Character received. Inform the owner
//
void CSerialPort::ReceiveChar(CSerialPort *port, COMSTAT comstat)
{
 BOOL bRead = TRUE;
 BOOL bResult = TRUE;
 DWORD dwError = 0;
 DWORD BytesRead = 0;
 unsigned char RXBuff;

 for (;;)
 {
  // Gain ownership of the comm port critical section.
  // This process guarantees no other part of this program
  // is using the port object.

  EnterCriticalSection(&port->m_csCommunicationSync);

  // ClearCommError() will update the COMSTAT structure and
  // clear any other errors.

  bResult = ClearCommError(port->m_hComm, &dwError, &comstat);

  LeaveCriticalSection(&port->m_csCommunicationSync);

  // start forever loop. I use this type of loop because I
  // do not know at runtime how many loops this will have to
  // run. My solution is to start a forever loop and to
  // break out of it when I have processed all of the
  // data available. Be careful with this approach and
  // be sure your loop will exit.
  // My reasons for this are not as clear in this sample
  // as it is in my production code, but I have found this
  // solutiion to be the most efficient way to do this.

  if (comstat.cbInQue == 0)
  {
   // break out when all bytes have been read
   break;
  }

  EnterCriticalSection(&port->m_csCommunicationSync);

  if (bRead)
  {
   bResult = ReadFile(port->m_hComm, // Handle to COMM port
    &RXBuff, // RX Buffer Pointer
    1, // Read one byte
    &BytesRead, // Stores number of bytes read
    &port->m_ov); // pointer to the m_ov structure
   // deal with the error code
   if (!bResult)
   {
    switch (dwError = GetLastError())
    {
     case ERROR_IO_PENDING:
     {
      // asynchronous i/o is still in progress
      // Proceed on to GetOverlappedResults();
      bRead = FALSE;
      break;
     }
     default:
     {
      // Another error has occured. Process this error.
      port->ProcessErrorMessage("ReadFile()");
      break;
     }
    }
   }
   else
   {
    // ReadFile() returned complete. It is not necessary to call GetOverlappedResults()
    bRead = TRUE;
   }
  } // close if (bRead)

  if (!bRead)
  {
   bRead = TRUE;
   bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port
    &port->m_ov, // Overlapped structure
    &BytesRead, // Stores number of bytes read
    TRUE); // Wait flag

   // deal with the error code
   if (!bResult)
   {
    port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
   }
  } // close if (!bRead)

  LeaveCriticalSection(&port->m_csCommunicationSync);

  // notify parent that a byte was received
  ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)RXBuff,(LPARAM)port->m_nPortNr);
 } // end forever loop

}

//
// Write a string to the port
//
void CSerialPort::WriteToPort(char *string)
{
 assert(m_hComm != 0);

 memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
 strcpy(m_szWriteBuffer, string);

 // set event for write
 SetEvent(m_hWriteEvent);
}

//
// Return the output buffer size
//
DWORD CSerialPort::GetWriteBufferSize()
{
 return m_nWriteBufferSize;
}

共5页。 9 7 1 2 3 4 5 8 :
网友关注
最新上市
编辑推荐
欢迎订阅天极网RSS聚合资讯:http://www.yesky.com/index.xml