多线程(2)

        MFC 支持多线程应用程序的开发,应用程序的每个线程都是一个 CWinThread 对象,MFC  将线程划分为两种类型:工作者线程(Worker  Thread)和用户界面线程(User_interface Thread),这两种类型都基于 CWinThread。
        如果线程需要执行后台计算而不需要与用户交互,那么该线程为工作者线程。工作者线程没有消息循环,不处理窗口消息,用于在后台执行任务。该类线程是最常用的类型。
        如果要处理用户输入并响应由用户产生的事件和消息,那么应该创建一个用户界面线程,它是通过自己的消息泵获取从系统接收消息。主线程本身就是一个用户界面线程,这是因为 CWinApp 派生于 CWinThread。用户可从 CWinThread 派生出自己的类来实现用户界面线程。

创建线程

创建线程主要有以下 3 种方法:
(1) Windows 的 API 函数 CreateThread;
(2) MFC 全局函数 AfxBeginThread;
(3) MFC 的 CWinThread 类的 CreateThread 成员函数。
以下就具体介绍这 3 种线程的创建方法。

1.使用 API 的 CreateThread( )函数

CreateThread( )函数建立进程的一个新线程。该函数的原型为:
 
HANDLE  CreateThread(
          LPSECURITY_ATTRIBUTES  lpThreadAttributes , 
          DWORD  dwStackSize , 
          LPTHREAD_START_ROUTINE  lpStartAddress , 
          LPVOID  lpParameter , 
          DWORD  dwCreationFlags , 
          LPDWORD  lpThreadId);
 
其中参数含义如下。
(1) lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构,用于指定线程的安全属性。如果使用默认安全属性,则置为 NULL。
(2) dwStackSize:指定线程用于堆分配堆栈的大小。如果为 0,则堆栈大小默认为和该进程的主线程的堆栈大小相同。
(3) lpStartAddress:指向新线程执行代码的开始地址,通常为包含线程代码的线程函数名。
(4) lpParameter:指定传递给线程函数的 32 位参数值。
(5)  dwCreationFlags:线程创建标志。如果为 CREATE_SUSPENDED,则该线程创建在挂起状态,直至调用 ResumeThread 函数后才运行;如果为 0,则创建后立即运行。
(6) lpThreadId:指向一个 32 位变量,用于接收该线程的标识符。

如果该函数调用成功,则返回新线程的句柄,否则返回 NULL。

  使用 CreateThread( )函数创建线程实例。

   // 线程主体函数  
   UNIT     ThreadProc(LPVOID pParam) 
{// 线程的实际代码  
 return 0; 
} 
HANDLE  hThread; 
DWORD  dwThreadID; 
DWORD  dwParam; 
hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc, 
                   wParam,0,&dwThreadID); 
if(hThread= =NULL) 
   MessageBox(" 创建线程错误 "); 

2.  使用 AfxBeginThread

        使用 AfxBeginThread 函数既可创建工作者线程又可创建用户界面线程。该函数有两种格式,第一种格式用于创建工作者线程,其中参数 pfnThreadProc  指向线程函数,pParam为传递给线程函数的参数。第二种格式用于创建用户界面线程,其中参数 pThreadClass 为CwinThread 派生对象的 RUNTIME_CLASS。
格式 1:
 
CWinThread  *AfxBeginThread(
          AFX_THREADPROC  pfnThreadProc,
          LPVOID   pParam,
          int  nPriority=THREAD_PRIORITY_NORMAL,
          UINT   nStackSize=0,
          DWORD   dwCreateFlags=0,
          LPSECURITY_ATTRIBUTES  lpSecurityAttrs=NULL
         );
 
格式 2:
 
CWinThread *AfxBeginThread(
          CRuntimeClass *pThreadClass,
          int  nPriority=THREAD_PRIORITY_NORMAL,
          UINT  nStackSize=0,
          DWORD   dwCreateFlags=0,
          LPSECURITY_ATTRIBUTES  lpSecurityAttrs=NULL
        );
 
该函数的返回值为指向新建线程对象的指针。例 10.2 为使用 AfxBeginThread 来创建进程的实例。

 【例 10.2】 使用 AfxBeginThread 来创建工作者线程和用户界面线程。 
 

// 线程函数  
    UNIT  ThreadProc(LPVOID  pParam) 
    {   // 线程代码  
        return  0; 
     } 
    // 在调用进程中创建工作者线程  
 CWinThread  *pThread; 
    DWORD  dwParam; 
    pThread=AfxBeginThread(ThreadProc,&dwParam); 
    if(pThread==NULL) 
      { MessageBox(" 创建错误 "); 
       // 错误处理  } 
      // 创建用户界面线程例  
      // 定义 CWinThread 线程派生类  
    class  CTestThread:public  CWinThread 
    {  //  } 
      // 在调用进程中创建用户界面线程  
    CTestThread  *pTestThread; 
    pTestThread=(CTestThread *)AfxBeginThread(RUNTIME_CLASS(CTestThread), THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);

3.使用 CWinThread 类 

        CWinThread 是 MFC 提供的线程对象类,包括创建、管理和删除的一系列成员变量和成员函数。CWinApp 是 CWinThread 的派生类。
        CWinThread 类支持工作者线程和用户界面线程。可以将一个指向 CWinThread 派生类的 CRuntimeClass 的指针作为参数传递给 AfxBeginThread 函数以创建一个用户界面线程。
         CWinThread  类的 CreateThread  成员函数创建一个在调用进程的地址空间中执行的线程。该函数原型为: 
                      BOOL  CreateThread(DWORD dwCreateFlags=0,UINT  nStackSize=0,  LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);
 
         若该函数成功创建了线程,返回非 0,否则返回 0。

 【例 10.3】 使用 CWinThread 类来创建线程。

CWinThread  thread;                    // 创建 CWinThread 对象  
thread.m_bAutoDelete=FALSE;          // 线程终止时不自动删除该对象  
thread.m_pfnThreadProc=ThreadProc;   // 设置线程函数  
thread.m_pThreadParams=&dwParam;      // 传递给线程函数的参数  
thread.CreateThrerad();              // 创建线程,参数使用默认值。  

 挂起线程

        使用 SuspendThread 和 ResumeThread 函数(Windows API 或 CWinThread 类成员函数),线程可以挂起或恢复另一个线程的运行。当线程处于挂起状态时,线程不会被调度运行。SuspendThread 函数将当前线程的挂起次数加 1。若该值的挂起次数大于 0,则该线程不运行。ResumeThread 函数将当前线程的挂起次数减 1。当该值为 0 时,线程恢复运行,否则线程仍处于挂起状态。如果将线程创建在挂起状态,那么在调用 ResumeThread  恢复执行之前可以完成对线程状态的初始化工作。
        另外可通过调用 Sleep 或 SleepEx 函数暂时挂起当前线程一段指定时间。它常用于线程与用户的交互中,通过延迟执行线程足够长的时间让用户观察其结果。在睡眠期间线程不会被调度执行。

终止线程

        可以调用ExitThread 函数或TerminateThread 函数终止线程的执行。与进程的终止相似,一般情况下使用 ExitThread   函数来终止线程,只有在不得已的情况下才使用
TerminateThread 来终止线程。
        可以调用全局函数 AfxEndThread  或者使用 return  语句来终止自己所在的线程。AfxEndThread 函数的原型为 AfxEndThread(UINT  nExitCode),其中参数 nExitCode 为线程的退出码,这个值为 0,表示成功,如果为其他值,那么表示各种不同类型的错误。可以通过函数 GetExitCodeThread 来获取线程的退出码。


 

你可能感兴趣的:(多线程(2))