(1) 在一个表示某种设备的C++类代码,其中创建了一个命名的“事件对象” bool SomeDevide::Open( int iPortNumber ) { 。。。 // Create the event that will get Set when data comes in for us to read m_hReadEvent = CreateEvent(NULL,FALSE,FALSE, L"Data Available for read" ); 。。。 } (2) 该设备类为了不断的和底层硬件通信(通过一个串口类实现)必须启动一个线程来读取设备发来的数据或者控制设备的状态。奇怪的是我光发现在该线程中使用了WaitForMultipleObjects(。。。)来等待(1)中创建的事件,但是在设备类中没有发现那句语句来设置该“事件”为有信号。 /** * Waits for data arrival event to be signalled from serial class instance in m_Serial * Once it gets notified of data arrival, it tries to read 128 chars */ static DWORD DevideWaitForReadThread( LPVOID pIn ) { HANDLE hEvents[2]; hEvents[0] = m_hReadEvent; hEvents[1] = m_hStopEvent; 。。。 // LOOP 1 : Wait for data to arrive and read it. do { DWORD dwEvent = WaitForMultipleObjects( 2, hEvents, FALSE, 1000 ); 。。。 } (3)最后才发现是通过 设备类 所依赖的 串口类 来向该“事件对象”发送信号的。这里面就用到了“命名事件对象”的技术了;如果在你的程序中有多处使用CreateEvent(。。。)创建同名的事件对象,那么在这些语句中只有第一次执行CreateEvent时windows系统才真正在内核中创建该事件的内核对象,后续语句都是返回先前创建的事件对象句柄。 【注】 HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPTSTR lpName ); Return Values A handle to the event object indicates success. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. NULL indicates failure. To get extended error information, call GetLastError. If lpName matches the name of an existing semaphore, mutex, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space. 我将串口类中的构造函数列于下面以供参考: EmbeddedSerial::EmbeddedSerial() { 。。。 /* Events to stop the read thread */ m_hStopReadThread = CreateEvent( NULL, FALSE, FALSE, L"Stop Read Thread" ); /* Events to signal that the read thread have stopped */ m_hReadThreadDown = CreateEvent( NULL, FALSE, FALSE, L"Read thread has shut down" ); m_hReadEvent = CreateEvent(NULL,FALSE,FALSE, L"Data Available for read" ); 。。。 } 以下是EmbededSerial类中提供的一个 线程入口函数: static DWORD ReadThread( LPVOID lp ); 该函数的定义如下: DWORD EmbeddedSerial::ReadThread( LPVOID lp ) { ((EmbeddedSerial*)lp)->ReadThreadObj(); return 0; } 该函数中调用的ReadThreadObj()定义如下: /* * The thread responsible for reading data. Waits for one of 2 events * An internal event to signal data arrival at the port - in which case it reads all available data from port into ring buffer * m_hStopReadThread - in which case th thread ends */ void EmbeddedSerial::ReadThreadObj( void ) { 。。。 DWORD dwWaitMask = EV_RXCHAR; DWORD dwError =0; unsigned char cTemp[READ_BLOCK_SIZE]; bool bLoop = true; SetCommMask(m_hCommPort, dwWaitMask ); do { if (WaitForSingleObject( m_hStopReadThread, 100) == WAIT_OBJECT_0) { // Quit the thread ?? bLoop = false; } else { DWORD dwMask; if( GetCommMask( m_hCommPort, &dwMask ) ) { if( EV_RXCHAR == (dwMask & EV_RXCHAR) ) { // Read data in blocks of 128 bytes do { ReadFile( m_hCommPort, cTemp, READ_BLOCK_SIZE,&dwBytesRead,NULL); if( dwBytesRead > 0 ) { // update the last tick count of read data m_TickCountAtLastRead = GetTickCount(); // Put the data into the ring buffer for Read data AddDataToRingBuffer(cTemp, dwBytesRead); // signal more data SetEvent(m_hReadEvent); //此处将信号 传递到 设备类 中。 } } while (dwBytesRead > 0 ); } } } } while( bLoop ); // End do. // Tell the dtr we have shut down SetEvent( m_hReadThreadDown ); } 【注】所有整个线程的交换过程是这样的: 串口(硬件接收器)接收到数据后会置位串口的状态位(状态寄存器)----->接着串口驱动程序(C++类实现的串口驱动程序)中的读写线程使用if( GetCommMask( m_hCommPort, &dwMask ) )取得当前串口的状态,以便判断是否接收到了数据,如果接受到数据则将数据放入串口驱动所维护的缓冲区中,并且通过 SetEvent(m_hReadEvent);将数据已经准备好信号发生到 设备类中------->然后由设备类中启动的设备线程读取串口线程所送上来的数据并进行后续解析。 |
|