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

2.工程实例 下面我们用第1节所述API实现一个多线程的串口通信程序。这个例子工程(工程名为MultiThreadCom)的界面很简单,如下图所示:
它是一个多线程的应用程序,包括两个工作者线程,分别处理串口1和串口2。为了简化问题,我们让连接两个串口的电缆只包含RX、TX两根连线(即不以硬件控制RS-232,串口上只会发生EV_TXEMPTY、EV_RXCHAR事件)。 在工程实例的BOOL CMultiThreadComApp::InitInstance()函数中,启动并设置COM1和COM2,其源代码为:
BOOL CMultiThreadComApp::InitInstance() { AfxEnableControlContainer(); //打开并设置COM1 hComm1=CreateFile("COM1", GENERIC_READ|GENERIC_WRITE, 0, NULL ,OPEN_EXISTING, 0,NULL); if (hComm1==(HANDLE)-1) { AfxMessageBox("打开COM1失败"); return false; } else { DCB wdcb; GetCommState (hComm1,&wdcb); wdcb.BaudRate=9600; SetCommState (hComm1,&wdcb); PurgeComm(hComm1,PURGE_TXCLEAR); } //打开并设置COM2 hComm2=CreateFile("COM2", GENERIC_READ|GENERIC_WRITE, 0, NULL ,OPEN_EXISTING, 0,NULL); if (hComm2==(HANDLE)-1) { AfxMessageBox("打开COM2失败"); return false; } else { DCB wdcb; GetCommState (hComm2,&wdcb); wdcb.BaudRate=9600; SetCommState (hComm2,&wdcb); PurgeComm(hComm2,PURGE_TXCLEAR); } CMultiThreadComDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } return FALSE; }
此后我们在对话框CMultiThreadComDlg的初始化函数OnInitDialog中启动两个分别处理COM1和COM2的线程:
BOOL CMultiThreadComDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here //启动串口1处理线程 DWORD nThreadId1; hCommThread1 = ::CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)Com1ThreadProcess, AfxGetMainWnd()->m_hWnd, 0, &nThreadId1); if (hCommThread1 == NULL) { AfxMessageBox("创建串口1处理线程失败"); return false; } //启动串口2处理线程 DWORD nThreadId2; hCommThread2 = ::CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)Com2ThreadProcess, AfxGetMainWnd()->m_hWnd, 0, &nThreadId2); if (hCommThread2 == NULL) { AfxMessageBox("创建串口2处理线程失败"); return false; } return TRUE; // return TRUE unless you set the focus to a control }
两个串口COM1和COM2对应的线程处理函数等待串口上发生事件,并根据事件类型和自身缓冲区是否有数据要发送进行相应的处理,其源代码为:
DWORD WINAPI Com1ThreadProcess(HWND hWnd//主窗口句柄) { DWORD wEven; char str[10]; //读入数据 SetCommMask(hComm1, EV_RXCHAR | EV_TXEMPTY); while (TRUE) { WaitCommEvent(hComm1, &wEven, NULL); if(wEven = 0) { CloseHandle(hCommThread1); hCommThread1 = NULL; ExitThread(0); } else { switch (wEven) { case EV_TXEMPTY: if (wTxPos < wTxLen) { //在串口1写入数据 DWORD wCount; //写入的字节数 WriteFile(hComm1, com1Data.TxBuf[wTxPos], 1, &wCount, NULL); com1Data.wTxPos++; } break; case EV_RXCHAR: if (com1Data.wRxPos < com1Data.wRxLen) { //读取串口数据, 处理收到的数据 DWORD wCount; //读取的字节数 ReadFile(hComm1, com1Data.RxBuf[wRxPos], 1, &wCount, NULL); com1Data.wRxPos++; if(com1Data.wRxPos== com1Data.wRxLen); ::PostMessage(hWnd, COM_SENDCHAR, 0, 1); } break; } } } } return TRUE; } DWORD WINAPI Com2ThreadProcess(HWND hWnd //主窗口句柄) { DWORD wEven; char str[10]; //读入数据 SetCommMask(hComm2, EV_RXCHAR | EV_TXEMPTY); while (TRUE) { WaitCommEvent(hComm2, &wEven, NULL); if (wEven = 0) { CloseHandle(hCommThread2); hCommThread2 = NULL; ExitThread(0); } else { switch (wEven) { case EV_TXEMPTY: if (wTxPos < wTxLen) { //在串口2写入数据 DWORD wCount; //写入的字节数 WriteFile(hComm2, com2Data.TxBuf[wTxPos], 1, &wCount, NULL); com2Data.wTxPos++; } break; case EV_RXCHAR: if (com2Data.wRxPos < com2Data.wRxLen) { //读取串口数据, 处理收到的数据 DWORD wCount; //读取的字节数 ReadFile(hComm2, com2Data.RxBuf[wRxPos], 1, &wCount, NULL); com2Data.wRxPos++; if(com2Data.wRxPos== com2Data.wRxLen); ::PostMessage(hWnd, COM_SENDCHAR, 0, 1); } break; } } } return TRUE; }
线程控制函数中所操作的com1Data和com2Data是与串口对应的数据结构struct tagSerialPort的实例,这个数据结构是: typedef struct tagSerialPort { BYTE RxBuf[SPRX_BUFLEN];//接收Buffer WORD wRxPos; //当前接收字节位置 WORD wRxLen; //要接收的字节数 BYTE TxBuf[SPTX_BUFLEN];//发送Buffer WORD wTxPos; //当前发送字节位置 WORD wTxLen; //要发送的字节数 }SerialPort, * LPSerialPort;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值