Yesky首页| 产品报价| 行情| 手机 | 数码 | 笔记本 | 台式机 | DIY硬件 | 外设 | 网络 | 数字家庭 | 评测 | 软件 | e时代 | 游戏 | 图片 | 壁纸 | 群乐 | 社区 | 博客 | 下载
软件频道>程序开发>JavaVBVCDelphiC/C++Web开发微软专栏移动数据库程序人生软件工程|产品中心下载开始设置Jazz Build
您现在的位置: 天极网 > 开发频道 > 深入浅出Win32多线程程序设计之综合实例
全文

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

2005-12-23 09:52 作者: 宋宝华 出处: 天极开发 责任编辑:方舟
  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;

共5页。 9 1 2 3 4 5 :
网友关注
最新上市
编辑推荐
欢迎订阅天极网RSS聚合资讯:http://www.yesky.com/index.xml