| |
深入浅出Win32多线程程序设计之综合实例 |
|
时间: 2005-12-23 来自:天极开发 |
 |
|
3.多线程串口类
使用多线程串口通信更方便的途径是编写一个多线程的串口类,例如Remon
Spekreijse编写了一个CSerialPort串口类。仔细分析这个类的源代码,将十分有助于我们对先前所学多线程及同步知识的理解。
3.1类的定义
#ifndef __SERIALPORT_H__ #define __SERIALPORT_H__
#define
WM_COMM_BREAK_DETECTED WM_USER+1 // A break was detected on
input. #define WM_COMM_CTS_DETECTED WM_USER+2 // The CTS
(clear-to-send) signal changed state. #define WM_COMM_DSR_DETECTED
WM_USER+3 // The DSR (data-set-ready) signal changed state. #define
WM_COMM_ERR_DETECTED WM_USER+4 // A line-status error occurred.
Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY. #define
WM_COMM_RING_DETECTED WM_USER+5 // A ring indicator was detected.
#define WM_COMM_RLSD_DETECTED WM_USER+6 // The RLSD
(receive-line-signal-detect) signal changed state. #define
WM_COMM_RXCHAR WM_USER+7 // A character was received and placed in the
input buffer. #define WM_COMM_RXFLAG_DETECTED WM_USER+8 // The event
character was received and placed in the input buffer. #define
WM_COMM_TXEMPTY_DETECTED WM_USER+9 // The last character in the output
buffer was sent.
class CSerialPort { public: //
contruction and destruction CSerialPort(); virtual
~CSerialPort();
// port initialisation BOOL InitPort(CWnd*
pPortOwner, UINT portnr = 1, UINT baud = 19200, char parity = 'N', UINT
databits = 8, UINT stopsbits = 1, DWORD dwCommEvents = EV_RXCHAR | EV_CTS,
UINT nBufferSize = 512);
// start/stop comm watching BOOL
StartMonitoring(); BOOL RestartMonitoring(); BOOL
StopMonitoring();
DWORD GetWriteBufferSize(); DWORD
GetCommEvents(); DCB GetDCB();
void WriteToPort(char*
string);
protected: // protected memberfunctions void
ProcessErrorMessage(char* ErrorText); static UINT CommThread(LPVOID
pParam); static void ReceiveChar(CSerialPort* port, COMSTAT
comstat); static void WriteChar(CSerialPort* port);
//
thread CWinThread* m_Thread;
// synchronisation
objects CRITICAL_SECTION m_csCommunicationSync; BOOL
m_bThreadAlive;
// handles HANDLE
m_hShutdownEvent; HANDLE m_hComm; HANDLE
m_hWriteEvent;
// Event array. // One element is used for
each event. There are two event handles for each port. // A Write
event and a receive character event which is located in the overlapped
structure (m_ov.hEvent). // There is a general shutdown when the port
is closed. HANDLE m_hEventArray[3];
//
structures OVERLAPPED m_ov; COMMTIMEOUTS
m_CommTimeouts; DCB m_dcb;
// owner window CWnd*
m_pOwner;
// misc UINT m_nPortNr; char*
m_szWriteBuffer; DWORD m_dwCommEvents; DWORD
m_nWriteBufferSize; };
#endif
__SERIALPORT_H__ | 3.2类的实现
3.2.1构造函数与析构函数
进行相关变量的赋初值及内存恢复:
CSerialPort::CSerialPort() { m_hComm = NULL;
//
initialize overlapped structure members to zero m_ov.Offset =
0; m_ov.OffsetHigh = 0;
// create events m_ov.hEvent =
NULL; m_hWriteEvent = NULL; m_hShutdownEvent =
NULL;
m_szWriteBuffer = NULL;
m_bThreadAlive =
FALSE; }
// // Delete dynamic
memory // CSerialPort::~CSerialPort() { do { SetEvent(m_hShutdownEvent); } while
(m_bThreadAlive);
TRACE("Thread ended\n");
delete
[]m_szWriteBuffer; } | 3.2.2核心函数:初始化串口
在初始化串口函数中,将打开串口,设置相关参数,并创建串口相关的用户控制事件,初始化临界区(Critical
Section),以成队的EnterCriticalSection()、LeaveCriticalSection()函数进行资源的排它性访问:
BOOL CSerialPort::InitPort(CWnd *pPortOwner, // the owner (CWnd) of
the port (receives message) UINT portnr, // portnumber (1..4) UINT
baud, // baudrate char parity, // parity UINT databits, //
databits UINT stopbits, // stopbits DWORD dwCommEvents, //
EV_RXCHAR, EV_CTS etc UINT writebuffersize) // size to the
writebuffer { assert(portnr > 0 && portnr <
5); assert(pPortOwner != NULL);
// if the thread is alive:
Kill if
(m_bThreadAlive) { do { SetEvent(m_hShutdownEvent); } while
(m_bThreadAlive); TRACE("Thread ended\n"); }
// create
events if (m_ov.hEvent !=
NULL) ResetEvent(m_ov.hEvent); m_ov.hEvent = CreateEvent(NULL,
TRUE, FALSE, NULL);
if (m_hWriteEvent !=
NULL) ResetEvent(m_hWriteEvent); m_hWriteEvent =
CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hShutdownEvent !=
NULL) ResetEvent(m_hShutdownEvent); m_hShutdownEvent =
CreateEvent(NULL, TRUE, FALSE, NULL);
// initialize the event
objects m_hEventArray[0] = m_hShutdownEvent; // highest
priority m_hEventArray[1] = m_ov.hEvent; m_hEventArray[2] =
m_hWriteEvent;
// initialize critical
section InitializeCriticalSection(&m_csCommunicationSync);
//
set buffersize for writing and save the owner m_pOwner =
pPortOwner;
if (m_szWriteBuffer != NULL) delete
[]m_szWriteBuffer; m_szWriteBuffer = new
char[writebuffersize];
m_nPortNr =
portnr;
m_nWriteBufferSize = writebuffersize; m_dwCommEvents
= dwCommEvents;
BOOL bResult = FALSE; char *szPort = new
char[50]; char *szBaud = new char[50];
// now it
critical! EnterCriticalSection(&m_csCommunicationSync);
//
if the port is already opened: close it if (m_hComm !=
NULL) { CloseHandle(m_hComm); m_hComm =
NULL; }
// prepare port strings sprintf(szPort, "COM%d",
portnr); sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud,
parity, databits,stopbits);
// get a handle to the
port m_hComm = CreateFile(szPort, // communication port string
(COMX) GENERIC_READ | GENERIC_WRITE, // read/write types 0, //
comm devices must be opened with exclusive access NULL, // no
security attributes OPEN_EXISTING, // comm devices must use
OPEN_EXISTING FILE_FLAG_OVERLAPPED, // Async I/O 0); // template
must be 0 for comm devices
if (m_hComm ==
INVALID_HANDLE_VALUE) { // port not found delete
[]szPort; delete []szBaud; return FALSE; }
// set
the timeout values m_CommTimeouts.ReadIntervalTimeout =
1000; m_CommTimeouts.ReadTotalTimeoutMultiplier =
1000; m_CommTimeouts.ReadTotalTimeoutConstant =
1000; m_CommTimeouts.WriteTotalTimeoutMultiplier =
1000; m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
//
configure if (SetCommTimeouts(m_hComm,
&m_CommTimeouts)) { if (SetCommMask(m_hComm,
dwCommEvents)) { if (GetCommState(m_hComm,
&m_dcb)) { m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set
RTS bit high! if (BuildCommDCB(szBaud,
&m_dcb)) { if (SetCommState(m_hComm,
&m_dcb)) ; // normal operation...
continue else ProcessErrorMessage("SetCommState()"); } else ProcessErrorMessage("BuildCommDCB()"); } else ProcessErrorMessage("GetCommState()"); } else ProcessErrorMessage("SetCommMask()"); } else ProcessErrorMessage("SetCommTimeouts()");
delete
[]szPort; delete []szBaud;
// flush the
port PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT
| PURGE_TXABORT);
// release critical
section LeaveCriticalSection(&m_csCommunicationSync);
TRACE("Initialisation
for communicationport %d completed.\nUse Startmonitor to communicate.\n",
portnr);
return TRUE; } |
|
|
|
|
|
|
|
|