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

来源:互联网 发布:南京逍遥游网络怎么样 编辑:程序博客网 时间:2024/05/01 17:08
2.工程实例下面我们用第1节所述API实现一个多线程的串口通信程序。这个例子工程(工程名为MultiThreadCom)的界面很简单,如下图所示:
它是一个多线程的应用程序,包括两个工作者线程,分别处理串口1和串口2。为了简化问题,我们让连接两个串口的电缆只包含RX、TX两根连线(即不以硬件控制RS-232,串口上只会发生EV_TXEMPTY、EV_RXCHAR事件)。在工程实例的BOOL CMultiThreadComApp::InitInstance()函数中,启动并设置COM1和COM2,其源代码为: BOOL CMultiThreadComApp::InitInstance(){AfxEnableControlContainer();//打开并设置COM1hComm1=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);}//打开并设置COM2hComm2=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 dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(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];//接收BufferWORD wRxPos; //当前接收字节位置WORD wRxLen; //要接收的字节数BYTE TxBuf[SPTX_BUFLEN];//发送BufferWORD wTxPos; //当前发送字节位置WORD wTxLen; //要发送的字节数}SerialPort, * LPSerialPort;
原创粉丝点击