ITPub博客

首页 > 应用开发 > IT综合 > 线程通信初探 (转)

线程通信初探 (转)

原创 IT综合 作者:worldblog 时间:2007-12-03 11:24:46 0 删除 编辑
线程通信初探 (转)[@more@]  进程是运行中的程序,有独立的内存文件句柄和其它的系统资源,一个独立的进程可以包含多条执行路径,即线程。一个函数可以被多个线程访问,多个线程可以访问同一个全局变量。
  windows提供两种线程,用户界面线程和辅助线程。用户界面线程有窗口,因此有自己的消息循环,辅助线程没有窗口,不需要处理消息。但是辅助线程非常有用而且很容易编程,比如程序在某个运行时间要完成多个(很笨重的)任务时,显然,辅助线程的使用会使程序的运行效率大大的提高。但是,线程间的通信是一个必须解决的问题。
  下面我们就来讨论一下线程间的通信的问题:
  一.线程的管理
  1.线程的启动:
  在使用辅助线程时,我们必须为线程写一个全局函数,它的返回值必须为  UINT类型,而且必须有LPVOID类型的参数,启动线程调用下面的函数:
  CWinThread* pThread=AfxBeginThread(
  AFX_THREADPPOC ThreadProc,
  LPVOID pParam,
  int nPriority,
  UINT nStackSize,
  Dword dwCreateFlags,
  LPSECURITY_ATTRIBUTES lpSecurityAttrs);
  全局函数必须定义为 UINT ThreadProc(LPVOID pParam);
  AfxBeginThread会立即返回一个指向新创建的线程对象的指针,用来管理线  程,包括挂起和恢复线程的运行,但是线程对象没有成员函数来中止线程的运  行。AfxBeginThread的第二个参数是一个32位的值,用来传给全局函数;第三  个参数用来设定线程的优先级;而第四和第六个参数用来指定线程堆栈大小和  安全性,一般采用默认值0;第五个参数用来设定创建线程对象的方式,0为立  即执行,CREATE_SUSPEND为线程通过ResumeThread后才执行。
  而线程优先级的设置和获得可以通过下面的两个函数来实现:
  pThread->SetThreadPriority(THREAD_PRIORITY_ABOVE_NOMAL);和
  int nPriority=pThread->GetThreadPriority();
  2.线程的中止:
  可以调用MFC的AfxEndThread函数;
  3.检查线程是否结束:
  调用api函数GetExitCodeThread,
  DWORD ExitCode ;
  ::GetExitCodeThread(pThread->m_hThread,&ExitCode );
  if(ExitCode==STILL_ACTIVE)
  //运行中
  else  //线程已经中止
  二.主线程和辅助线程的通信
  主线程和辅助线程间的通信方式有很多种,最简单的就是利用全局变量。  这里利用消息通信是行不通的,因为辅助线程没有消息循环,不能够利用  Windows消息。
  下面我们用一个例子来说明。在例子中,我们写一个非常笨的函数,如实  现500*3000*3000的加法数据处理函数Add(int nCount);
  我们在对话框上放置Start、Cancel按钮和一个用来表示数据处理进度的进度条  。
  1.利用全局变量来实现主线程和辅助线程的通信:
  我们编写全局函数如下:
  UINT ThreadProc(LPVOID pParam)
  {
  nCount=0;//全局变量
  while(nCount<500)
  {
  Add(nCount);
  ::InterlockedIncrement((long*)&ncount);
  }
  return 0;
  }
  函数InterlockIncrement阻塞其它的线程,当计数器递增时防止其它的线程访问nCount。
  2.利用消息实现辅助线程和主线程的通信:
  主线程有一个窗口,有消息循环,我们可以在调用AfxBeginThread时把窗口句柄传递给辅助线程,我们通过post方式传递消息,在函数退出时,给窗口发送一个消息。
  重新编写线程函数如下:
  int nCount=0;
  UINT ThreadProc(LPVOID pParam)
  {
   while(nCount<500)
   {
   ::InterlockedIncrement((long*)&ncount);
   Add(nCount);
   }
   ::PostMessage(
    (HWND)pParam,
    WM_THREADFINISHED,//用户自定义消息
    0,0);
    return 0;
  }
  编写OnStart函数:
  void CThreadDlg::OnStart()
  {
   m_nTimer=SetTimer(1,100,NULL);//0.1秒
   ASSERT(m_nTimer!=0);
   GetDlgItem(IDC_START)->EnableWindow(FALSE);
   AfxBeginThread(ThreadProc,GetSafeHwnd(),THREAD_PROIRITY_NOMAL);
  }
  编辑OnCancel函数如下:
  void CThreadDlg::OnCancel()
  {
   if(nCount==0)
    CDialog::OnCancel();
   else nCount=500;
  }
  处理OnThreadFinished函数
  HRESULT CThreadDlg::OnThreadFinished(WPARAM wParam,LPARAM lParam)
  {
   CDialog::OnOk();
   return 0;
  }
  3.用事件使线程同步:
  利用WaitForSingleobject函数
  在stdafx.h中写入下面一行
  #include //由于使用了事件
  声明两个全局变量
  CEvent m_start,m_kill;
  在初始化函数中启动线程;
  重新编写OnStart函数:
  void CThreadDlg::OnStart()
  {
   m_nTimer=SetTimer(1,100,NULL);//0.1秒
   ASSERT(m_nTimer!=0);
   GetDlgItem(IDC_START)->EnableWindow(FALSE);
   m_start.SetEvent();
  } 
  重新编辑OnCancel函数如下:
  void CThreadDlg::OnCancel()
  {
   if(nCount==0)
    m_start.SetEvent();
   else m_kill.SetEvent();
  }
  编写全局函数如下:
  UINT ThreadProc(LPVOID pParam)
  {
   ::WaitForSingleObject(m_start,INFINITE);
   while(nCount<500)
   {
   Add(nCount);
   if(::WaitForSingleObject(m_start,0)=WAIT_OBJECT_0)
    break;
   }
   ::PostMessage(
    (HWND)pParam,
    WM_THREADFINISHED,//用户自定义消息
    0,0);
    return 0;
  } 
  其中第一个WaitForSingleObject的调用等待启动事件,INFINITE使其等待直到启动事件有信号。第二个调用若有信号,立即返回,中止线程。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-987652/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    6241
  • 访问量
    2462345