乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      采用_beginthread/_beginthreadex函數(shù)創(chuàng)建多線程

       wtkc 2014-11-20

      1、CRT簡介:

      CRT: (C Runtime Library)即C運行時庫,是系統(tǒng)運行的基礎(chǔ),包含了c常用的函數(shù)集(如:printf,malloc,strcpy等),為運行main做了初始化環(huán)境變量、堆、io等資源,并在結(jié)束后清理。

      在Windows環(huán)境下,VC提供的 C run-time library又分為動態(tài)運行時庫、靜態(tài)運行時庫、多線程、單線程、調(diào)試版本(Debug)、發(fā)行版本(Release)等。

       開關(guān)

      對應(yīng)的庫

      版本

         /MD

      MSVCRT.LIB

      多線程DLLRelease版本

         /MDd

      MSCVRTD.LIB

      多線程DLLDebug版本

         /MT

      LIBCMT.LIB

      多線程靜態(tài)鏈接的Release版本

         /MTd

      LIBCMTD.LIB

      多線程靜態(tài)鏈接的Debug版本

         /clr

      MSVCMRT.LIB

      托管代碼和非托管代碼混合

         /clr:pure

      MSVCURT.LIB

      純托管代碼

      圖1:編譯器運行庫設(shè)置(VS2008)

      具體請參考MSDN:

      ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_vccrt/html/a889fd39-807d-48f2-807f-81492612463f.htm

      2、使用CRT的多線程函數(shù)集:兩組

      序號

      函數(shù)名

      功能

      1

      _beginthread()

      創(chuàng)建一個新線程

      2

      _endthread()

      結(jié)束一個線程的執(zhí)行

      3

      _beginthreadex()

      創(chuàng)建一個新線程

      4

      _endthreadex()

      結(jié)束一個線程的執(zhí)行

      5

      ResumeThread()

      恢復(fù)線程的運行

      6

      SuspendThread()

      掛起線程

      7

      GetExiCodeThread()

      得到一個線程的退出碼

      8

      WaitForSingleObject()

      等待單個對象

      9

      WaitForMultipleObjects()

      等待多個對象

      3、兩組函數(shù)的說明:

      3.1、_beginthread和_endthread
      該函數(shù)是C Runtime Library中的函數(shù)。其原型如下

      unsigned long _beginthread(

      void( __cdecl *start_address )( void * ),//線程函數(shù)的起始地址

      unsigned stack_size,//堆棧大小,設(shè)置0為系統(tǒng)默認(rèn)值

      void *arglist );//傳遞給線程函數(shù)的參數(shù),沒有則為NULL

      “該函數(shù)被認(rèn)為是頭腦簡單的函數(shù)”,使用該函數(shù)導(dǎo)致無法有效的控制被創(chuàng)建線程,如不能在啟動時將該線程掛起,無法為該線程設(shè)置優(yōu)先權(quán)等。另外,無法利用這個Handle來等待該線程結(jié)束等操作。該函數(shù)是早期的C Runtime Library的產(chǎn)物,不提倡使用,后期的改良版本為_beginthreadex。
      通過_beginthread啟動的線程在應(yīng)當(dāng)通過調(diào)用_endthread結(jié)束,以保證清除與線程相關(guān)的資源。_endthread的原型為:

      void _endthread(void);

       

      3.2、_beginthreadex和_endthreadex
      該函數(shù)是C Runtime Library中的一個函數(shù),用標(biāo)準(zhǔn)C實現(xiàn),相比_beginthread,_beginthreadex對線程控制更為有力(比前者多三個參數(shù)),是_beginthread的加強(qiáng)版。其原型為:

      unsignedlong _beginthreadex(

      void *security,//線程函數(shù)的安全描述符

      unsigned stack_size,// 堆棧大小,設(shè)置0為系統(tǒng)默認(rèn)值

      unsigned ( __stdcall *start_address )( void * ),//線程函數(shù)的起始地址

      void*arglist, //傳遞給線程函數(shù)的參數(shù),沒有則為NULL

      unsignedinitflag,//初始狀態(tài),0為立即執(zhí)行,CREATE_SUSPEND為創(chuàng)建后掛起

      unsigned*thrdaddr );//指向一個32為的變量,存放線程標(biāo)識符

      該函數(shù)返回新線程的句柄,通過該句柄可實現(xiàn)對線程的控制。雖然,該函數(shù)是用標(biāo)準(zhǔn)C寫的(即可不加修改就可以移植到其他系統(tǒng)執(zhí)行),但是由于它與Windows系統(tǒng)有著緊密的聯(lián)系(需要手動關(guān)閉該線程產(chǎn)生的Handle),因此實現(xiàn)時,往往需要包含windows.h。
      通過_beginthreadex啟動的線程通過調(diào)用_endthreadex做相關(guān)清理。該函數(shù)比較像CreateThread函數(shù)。

      _endthreadex函數(shù)的原型為:

      void _endthreadex(unsigned retVal);

      關(guān)于這兩組函數(shù)的詳細(xì)區(qū)別請參考MSDN的說明:

      Creates a thread.

      uintptr_t _beginthread(

         void( *start_address )( void * ),

         unsigned stack_size,

         void *arglist

      );

      uintptr_t _beginthreadex(

         void *security,

         unsigned stack_size,

         unsigned ( *start_address )( void * ),

         void *arglist,

         unsigned initflag,

         unsigned *thrdaddr

      );

      Parameters

      start_address

      Start address of a routine that begins execution of a new thread.For _beginthread, the calling convention is either__cdecl or __clrcall; for _beginthreadex, it iseither __stdcall or __clrcall.

      stack_size

      Stack size for a new thread or 0.

      arglist

      Argument list to be passed to a new thread or NULL.

      security

      Pointer to a SECURITY_ATTRIBUTES structure that determines whetherthe returned handle can be inherited by child processes. If NULL, the handlecannot be inherited. Must be NULL for Windows 95 applications.

      initflag

      Initial state of a new thread (0 forrunning or CREATE_SUSPENDED for suspended); useResumeThread to execute the thread.

      thrdaddr

      Points to a 32-bit variable that receives the thread identifier.Might be NULL, in which case it is not used.

      Return Value

      If successful, each of these functions returns a handle to thenewly created thread; however, if the newly created thread exits too quickly, _beginthread might not return a valid handle (see thediscussion in the Remarks section). _beginthread returns -1L on an error, in which case errno is set to EAGAIN if thereare too many threads, to EINVAL if the argument isinvalid or the stack size is incorrect, or to EACCESin the case of insufficient resources (such as memory). _beginthreadexreturns 0 on an error, in which case errno and _doserrno are set.

      If startaddress is NULL, the invalid parameter handler is invoked, asdescribed in Parameter Validation. If execution is allowed to continue, these functions set errno to EINVAL and return -1.

      For more information about these and other return codes, see_doserrno, errno, _sys_errlist, and _sys_nerr.

      For more information about uintptr_t,see Standard Types.

      Remarks

      The _beginthread function creates athread that begins execution of a routine at start_address.The routine at start_address must use the __cdecl calling convention and should have no returnvalue. When the thread returns from that routine, it is terminatedautomatically. For more information about threads, see Multithreading.

      _beginthreadex resembles the Win32 CreateThread API more closely than _beginthread does. _beginthreadexdiffers from _beginthread in the following ways:

      ·        _beginthreadex has three additional parameters: initflag,security, and threadaddr.The new thread can be created in a suspended state, with a specified security(Windows NT only), and can be accessed using thrdaddr,which is the thread identifier.

      ·        The routine at start_address passed to _beginthreadexmust use the __stdcall calling convention and mustreturn a thread exit code.

      ·        _beginthreadex returns 0 on failure, rather than -1L.

      ·        A thread created with _beginthreadex is terminated by a call to _endthreadex.

      The _beginthreadex function gives you morecontrol over how the thread is created than _beginthreaddoes. The _endthreadex function is also moreflexible. For example, with _beginthreadex, you canuse security information, set the initial state of the thread (running orsuspended), and get the thread identifier of the newly created thread. You arealso able to use the thread handle returned by _beginthreadexwith the synchronization APIs, which you cannot do with _beginthread.

      It is safer to use _beginthreadex than _beginthread. If the thread generated by _beginthread exits quickly, the handle returned to thecaller of _beginthread might be invalid or, worse,point to another thread. However, the handle returned by _beginthreadexhas to be closed by the caller of _beginthreadex, soit is guaranteed to be a valid handle if _beginthreadexdid not return an error.

      You can call _endthread or _endthreadex explicitly to terminate athread; however, _endthread or _endthreadexis called automatically when the thread returns from the routine passed as aparameter. Terminating a thread with a call to endthreador _endthreadex helps to ensure proper recovery ofresources allocated for the thread.

      _endthread automatically closes the thread handle (whereas _endthreadex does not). Therefore, when using _beginthread and _endthread, donot explicitly close the thread handle by calling the Win32 CloseHandle API.This behavior differs from the Win32 ExitThread API.

      Note:

      For an executable file linked with Libcmt.lib , do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.

      The operating system handles the allocation of the stack wheneither _beginthread or _beginthreadexis called; you do not need to pass the address of the thread stack to either ofthese functions. In addition, the stack_sizeargument can be 0, in which case the operating system uses the same value asthe stack specified for the main thread.

      arglist is a parameter to be passed to the newly created thread.Typically it is the address of a data item, such as a character string. arglist can be NULL if it isnot needed, but _beginthread and _beginthreadex must be provided with some value to pass tothe new thread. All threads are terminated if any thread calls abort, exit, _exit, or ExitProcess.

      The locale of the new thread is inherited from its parent thread.If per thread locale is enabled by a call to _configthreadlocale (eitherglobally or for new threads only), the thread can change its localeindependently from its parent by calling setlocaleor _wsetlocale. For more information, see Locale.

      For mixed and pure code, _beginthreadand _beginthreadex both have two overloads, onetaking a native calling-convention function pointer, the other taking a __clrcall function pointer. The first overload is notapplication domain-safe and never will be. If you are writing mixed or purecode you must ensure that the new thread enters the correct application domainbefore it accesses managed resources. You can do this, for example, by usingcall_in_appdomain Function. The second overload is application domain-safe; thenewly created thread will always end up in the application domain of the callerof _beginthread or _beginthreadex.

      Requirements

      Routine

      Required header

      _beginthread

      <process.h>

      _beginthreadex

      <process.h>

      For more compatibility information, see Compatibility in theIntroduction.

      Libraries

      Multithreaded versions of the C run-time libraries only.

      3.3、線程函數(shù)的定義:

      _beginthread()和_beginthreadex()的線程執(zhí)行函數(shù)的定義是不一樣的。

      對于_beginthread()創(chuàng)建的線程,其線程函數(shù)定義為:

      void ThreadPro(void * pArguments );

      對于_beginthreadex()創(chuàng)建的線程,其線程函數(shù)定義為:

      unsigned __stdcallThreadFunc( void* pArguments )

      4、注意事項:

      (1)兩者創(chuàng)建線程函數(shù)方式不同,_beginthreadex()的線程函數(shù)必須使用__stdcall調(diào)用方式,而且必須返回一個unsigned型的退出碼。

      (2)_beginthreadex()在創(chuàng)建線程失敗時返回0,而_beginthread()在創(chuàng)建線程失敗時返回-1,這一點在檢測返回結(jié)果時必須注意。

      (3)如果是調(diào)用_beginthread()創(chuàng)建線程,并相應(yīng)地調(diào)用_endthread()結(jié)束線程時,系統(tǒng)將自動關(guān)閉線程句柄。而調(diào)用_beginthreadex()創(chuàng)建線程,并相應(yīng)地調(diào)用_endthreadex()結(jié)束線程時,系統(tǒng)不能自動關(guān)閉線程句柄。

      (4)由于_beginthread()創(chuàng)建線程參數(shù)比較簡單,不能控制線程的初始啟動狀態(tài),且不返回創(chuàng)建的線程句柄,也不能調(diào)用

      WaitForSingleObject()/WaitForMultipleObjects()函數(shù)。所以一般不常用,而_beginthreadex()與CreatThread()函數(shù)比較相似。能方便控制線程。

       

      5、多線程實例:

      5.1、實例1:

      實例說明:該實例主要使用_beginthread()函數(shù),創(chuàng)建盡可能多的線程,知道系統(tǒng)不能再創(chuàng)建為止。注意實時數(shù)據(jù)的顯示和參數(shù)的傳遞,如果想傳遞多個參數(shù),則可以使用結(jié)構(gòu)體。

      主要函數(shù)如下:

      //在.h文件中:

      #define WM_ADD WM_USER+10//定義消息

      void ThreadFunc1(void *pArg);//線程函數(shù)1:開始創(chuàng)建

      void ThreadFunc2(void *pArg);//線程函數(shù)2

      LRESULT OnMyMsg(WPARAM, LPARAM);//消息函數(shù)  

       

      //在.cpp文件中:

      //全局變量,一般在cpp中定義,不要在.h定義,否則編譯出錯:變量重復(fù)定義

      bool g_bRun = false;

      long g_nCount = 0;

       

      //開始按鈕函數(shù)

      void C_beginthreadDlg::OnBnClickedButtonRun()

      {

          // TODO: 在此添加控件通知處理程序代碼

          //創(chuàng)建線程:主要是用來創(chuàng)建執(zhí)行創(chuàng)建線程池的線程

          if (_beginthread(ThreadFunc1,0,&m_hWnd) != -1 )

          {//成功

             GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(FALSE);

          }

      }

       

      //創(chuàng)建線程池的線程函數(shù)

      void ThreadFunc1(void *pArg)

      {

          HWND *hWnd = (HWND*)pArg;//得到窗口句柄

          g_nCount= 0;//初始化變量

          g_bRun = true;

          while (g_bRun)

          {//開始創(chuàng)建盡可能多的線程

             if (_beginthread(ThreadFunc2,0,hWnd) == -1)

             {//失敗則結(jié)束

                 g_bRun= false;

                 break;

             }

          }

          //退出

          ::SendMessage(*hWnd,WM_ADD,1,0); 

      }

       

      //線程函數(shù)

      void ThreadFunc2(void *pArg)

      {

          HWND *hWnd = (HWND*)pArg;

          g_nCount++;

          ::SendMessage(*hWnd,WM_ADD,0,g_nCount);//顯示個數(shù)

          while(g_bRun)

          {

             Sleep(1000);

          }

      }

       

      // WM_ADD消息處理函數(shù)

      LRESULT C_beginthreadDlg::OnMyMsg(WPARAM wParam, LPARAM lParam)

      {

          if (wParam == 1)

          {//結(jié)束

             GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(TRUE);

          }

          else

          {//顯示更新

             m_nCount= g_nCount;

              UpdateData(FALSE);

          }

          return 0;

      }

       

      運行效果:

      圖2:實例1演示

      工程源碼下載地址:

      http://download.csdn.net/detail/cbnotes/4902781

      歡迎大家修改和指正。

      注意事項:

      (1)由于_beginthread()創(chuàng)建的線程結(jié)束后自動關(guān)閉線程句柄,所以不能使用WaitForSingleObject()/WaitForMultipleObjects()函數(shù)來同步。

      (2)上面的程序中,先是創(chuàng)建了線程1(ThreadFunc1),再用該線程1來創(chuàng)建眾多線程,而不是直接在OnBnClickedButtonRun()函數(shù)中創(chuàng)建眾多線程,大家知道這是為什么嗎?主要是為了能夠實時顯示創(chuàng)建的線程數(shù)目。如果直接在OnBnClickedButtonRun()函數(shù)中創(chuàng)建眾多線程,主線程將一直處于while循環(huán)中,而不能及時處理消息,所以就不能實時顯示創(chuàng)建的線程數(shù)目(不信的話大家可以試試)。

      (3)注意線程函數(shù)參數(shù)的傳遞,和消息的發(fā)送。如果要傳遞多個參數(shù),可以使用結(jié)構(gòu)體傳遞。

      5.2、實例2:

      實例說明:該實例主要使用_beginthreadex()函數(shù),多人合作(5人)共同完成一項任務(wù),即平時大家說的分工合作,齊頭并進(jìn)。

      主要函數(shù)如下:

      //.h文件中

      //聲明線程處理函數(shù)

      unsigned __stdcall ThreadFunc1( void*pArguments );//合作工作線程函數(shù)

      unsigned __stdcall ThreadFunc2( void*pArguments );//檢測工作完成線程函數(shù)

       

      //為了傳遞多個參數(shù),我采用結(jié)構(gòu)體

      struct threadInfo

      {

          HWND hWnd;       //窗口句柄

          int  nOffset;    //偏移量

          int  nWidth;     //寬度

      };

       

      struct threadInfo2

      {

          HWND   hWnd;           //窗口句柄

          HANDLE *phHandle;     //線程句柄指針

      };

      // 實現(xiàn)

      protected:

          threadInfoInfo[5];

          HANDLE m_hThead[5];    //用于存儲線程句柄

          HANDLE hThead;     //用于存儲線程句柄

          unsigned  m_dwThreadID[5];//用于存儲線程的ID

         threadInfo2Info2;

      //在.cpp文件中

      //開始按鈕函數(shù)

      void C_beginthreadexDlg::OnBnClickedButtonRun()

      {

          // TODO: 在此添加控件通知處理程序代碼

          //使能開始按鈕:無效

          GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(FALSE);

          CDC *dc = GetDC();

          CRect rt;

          GetClientRect(rt);

          dc->FillSolidRect(0,0,rt.Width(),200,RGB(240,240,240));//刷新背景

          ReleaseDC(dc);

          int nWidth = rt.Width()/5;

          //初始化線程的參數(shù)

          Info[0].hWnd = Info[1].hWnd = Info[2].hWnd = Info[3].hWnd = Info[4].hWnd = GetSafeHwnd();

          Info[0].nOffset = 0;Info[1].nOffset = nWidth;Info[2].nOffset= 2*nWidth;Info[3].nOffset = 3*nWidth;Info[4].nOffset= 4*nWidth;

          Info[0].nWidth = Info[1].nWidth = Info[2].nWidth = Info[3].nWidth = Info[4].nWidth = nWidth;

          //創(chuàng)建個模擬線程

          for (int i = 0;i<5;i++)

          {  

             m_hThead[i] = (HANDLE)_beginthreadex(NULL,0,ThreadFunc1,&Info[i],CREATE_SUSPENDED,&m_dwThreadID[i]); 

          }

          GetDlgItem(IDC_STATIC1)->SetWindowText("進(jìn)行中...");

          //開始運行

          for (int i = 0;i<5;i++)

          {  

             ResumeThread(m_hThead[i]); 

          }

          //開始運行監(jiān)測結(jié)果線程

          Info2.hWnd = m_hWnd;

          Info2.phHandle = m_hThead;

          hThead =(HANDLE)_beginthreadex(NULL,0,ThreadFunc2,&Info2,0,NULL);

      }

       

      //合作工作線程函數(shù)

      unsigned __stdcall ThreadFunc1( void*pArguments )

      {

          threadInfo*info = (threadInfo*)pArguments;

          CDC *dc = CWnd::FromHandle(info->hWnd)->GetDC();

          for (int i=info->nOffset;i<info->nOffset+info->nWidth;i++)

          {

             for (int j =0 ;j<200;j++)

             {  

                 dc->SetPixel(i,j,RGB(0,0,0));

             }

          }

          DeleteObject(dc);

          return 0;

      }

       

      //等待所有的工作結(jié)束

      unsigned __stdcall ThreadFunc2( void*pArguments )

      {

          threadInfo2*info = (threadInfo2*)pArguments;

          //等待個線程中的一個完成

          DWORD dwRet = WaitForMultipleObjects(5,info->phHandle,TRUE,INFINITE);

          if (dwRet == WAIT_FAILED)

          {//出錯啦

             ::SendMessage(info->hWnd,WM_GAMEOVER,1,0);

             return 0;

          }

          //完成結(jié)束

          ::SendMessage(info->hWnd,WM_GAMEOVER,0,0);

          return 0;

      }

       

       

      //消息處理函數(shù)

      LRESULT C_beginthreadexDlg::OnGameOver(WPARAMwParam, LPARAMlParam)

      {

          if (wParam ==1)

          {//出錯

             GetDlgItem(IDC_STATIC1)->SetWindowText("出錯啦!");

          }

          else

          {//成功

             //顯示結(jié)果

             GetDlgItem(IDC_STATIC1)->SetWindowText("任務(wù)完成!");

             //閃動顯示

             CDC *dc = GetDC();

             CRect rt;

             GetClientRect(rt);

             for (int i=0;i<8;i++)

             {

                 dc->Draw3dRect(0,0,rt.Width(),200,RGB(240,240,240),RGB(240,240,240));//刷新背景

                 dc->Draw3dRect(1,1,rt.Width()-1,199,RGB(240,240,240),RGB(240,240,240));//刷新背景

                 Sleep(100);

                 dc->Draw3dRect(0,0,rt.Width(),200,RGB(255,0,0),RGB(255,0,0));//刷新背景

                 dc->Draw3dRect(1,1,rt.Width()-1,199,RGB(255,0,0),RGB(255,0,0));//刷新背景

                 Sleep(100);

             }

             ReleaseDC(dc);

          }

          //關(guān)閉句柄

          for (int i=0;i<5;i++)

          {

             CloseHandle(m_hThead[i]);

          }

          CloseHandle(hThead);

          //使能開始按鈕,以便可以開始下一次比賽

          GetDlgItem(IDC_BUTTON_RUN)->EnableWindow(TRUE);

          return 0;

      }

      運行效果:

      工程源碼下載地址:

      http://download.csdn.net/detail/cbnotes/4905693

      歡迎大家修改和指正。

      注意事項:

      (1)由于_beginthreadex()創(chuàng)建的線程結(jié)束后自動調(diào)用_endthreadex()函數(shù),但是不會關(guān)閉線程句柄,所以必須手動關(guān)閉句柄,但能使用同步函數(shù),如:

      WaitForSingleObject()/WaitForMultipleObjects()函數(shù)來同步。

      (2)通過該實例還可以稍加改進(jìn),就可以統(tǒng)計5個線程的各自的工作時間,并排序。歡迎大家多多練習(xí)。

      (3)由_beginthreadex()函數(shù)創(chuàng)建線程,能靈和控制和管理線程,所以推薦使用該方式。

      =================================================轉(zhuǎn)載請標(biāo)明出處,謝謝.http://blog.csdn.net/cbNotes

       

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多