进程是运行中的程序,有独立的内存,文件句柄和其它的系统资源,一个独立的进程可以包含多条执行路径,即线程。一个函数可以被多个线程访问,多个线程可以访问同一个全局变量。 
     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 <afxmt.h>//由于使用了事件 
        声明两个全局变量 
           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使其等待直到启动事件有信号。第二个调用若有信号,

posted on 2013-09-02 20:50  言止予思  阅读(131)  评论(0编辑  收藏  举报