(1) 在一個表示某種設(shè)備的C++類代碼,其中創(chuàng)建了一個命名的“事件對象” 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) 該設(shè)備類為了不斷的和底層硬件通信(通過一個串口類實現(xiàn))必須啟動一個線程來讀取設(shè)備發(fā)來的數(shù)據(jù)或者控制設(shè)備的狀態(tài)。奇怪的是我光發(fā)現(xiàn)在該線程中使用了WaitForMultipleObjects(。。。)來等待(1)中創(chuàng)建的事件,但是在設(shè)備類中沒有發(fā)現(xiàn)那句語句來設(shè)置該“事件”為有信號。 /** * 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)最后才發(fā)現(xiàn)是通過 設(shè)備類 所依賴的 串口類 來向該“事件對象”發(fā)送信號的。這里面就用到了“命名事件對象”的技術(shù)了;如果在你的程序中有多處使用CreateEvent(。。。)創(chuàng)建同名的事件對象,那么在這些語句中只有第一次執(zhí)行CreateEvent時windows系統(tǒng)才真正在內(nèi)核中創(chuàng)建該事件的內(nèi)核對象,后續(xù)語句都是返回先前創(chuàng)建的事件對象句柄。 【注】 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. 我將串口類中的構(gòu)造函數(shù)列于下面以供參考: 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類中提供的一個 線程入口函數(shù): static DWORD ReadThread( LPVOID lp ); 該函數(shù)的定義如下: DWORD EmbeddedSerial::ReadThread( LPVOID lp ) { ((EmbeddedSerial*)lp)->ReadThreadObj(); return 0; } 該函數(shù)中調(diào)用的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); //此處將信號 傳遞到 設(shè)備類 中。 } } while (dwBytesRead > 0 ); } } } } while( bLoop ); // End do. // Tell the dtr we have shut down SetEvent( m_hReadThreadDown ); } 【注】所有整個線程的交換過程是這樣的: 串口(硬件接收器)接收到數(shù)據(jù)后會置位串口的狀態(tài)位(狀態(tài)寄存器)----->接著串口驅(qū)動程序(C++類實現(xiàn)的串口驅(qū)動程序)中的讀寫線程使用if( GetCommMask( m_hCommPort, &dwMask ) )取得當(dāng)前串口的狀態(tài),以便判斷是否接收到了數(shù)據(jù),如果接受到數(shù)據(jù)則將數(shù)據(jù)放入串口驅(qū)動所維護的緩沖區(qū)中,并且通過 SetEvent(m_hReadEvent);將數(shù)據(jù)已經(jīng)準(zhǔn)備好信號發(fā)生到 設(shè)備類中------->然后由設(shè)備類中啟動的設(shè)備線程讀取串口線程所送上來的數(shù)據(jù)并進行后續(xù)解析。 |
|