• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            C++ Programmer's Cookbook

            {C++ 基礎(chǔ)} {C++ 高級} {C#界面,C++核心算法} {設(shè)計模式} {C#基礎(chǔ)}

            C++多線程(二)

            C/C++ Runtime 多線程函數(shù)

            一 簡單實例(來自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
            主線程創(chuàng)建2個線程t1和t2,創(chuàng)建時2個線程就被掛起,后來調(diào)用ResumeThread恢復(fù)2個線程,是其開始執(zhí)行,調(diào)用WaitForSingleObject等待2個線程執(zhí)行完,然后推出主線程即結(jié)束進(jìn)程。

            /*  file Main.cpp
             *
             *  This program is an adaptation of the code Rex Jaeschke showed in
             *  Listing 1 of his Oct 2005 C/C++ User's Journal article entitled
             *  "C++/CLI Threading: Part I".  I changed it from C++/CLI (managed)
             *  code to standard C++.
             *
             *  One hassle is the fact that C++ must employ a free (C) function
             *  or a static class member function as the thread entry function.
             *
             *  This program must be compiled with a multi-threaded C run-time
             *  (/MT for LIBCMT.LIB in a release build or /MTd for LIBCMTD.LIB
             *  in a debug build).
             *
             *                                      John Kopplin  7/2006
             
            */



            #include 
            <stdio.h>
            #include 
            <string>             // for STL string class
            #include <windows.h>          // for HANDLE
            #include <process.h>          // for _beginthread()

            using namespace std;


            class ThreadX
            {
            private:
              
            int loopStart;
              
            int loopEnd;
              
            int dispFrequency;

            public:
              
            string threadName;

              ThreadX( 
            int startValue, int endValue, int frequency )
              
            {
                loopStart 
            = startValue;
                loopEnd 
            = endValue;
                dispFrequency 
            = frequency;
              }


              
            // In C++ you must employ a free (C) function or a static
              
            // class member function as the thread entry-point-function.
              
            // Furthermore, _beginthreadex() demands that the thread
              
            // entry function signature take a single (void*) and returned
              
            // an unsigned.
              static unsigned __stdcall ThreadStaticEntryPoint(void * pThis)
              
            {
                  ThreadX 
            * pthX = (ThreadX*)pThis;   // the tricky cast
                  pthX->ThreadEntryPoint();           // now call the true entry-point-function

                  
            // A thread terminates automatically if it completes execution,
                  
            // or it can terminate itself with a call to _endthread().

                  
            return 1;          // the thread exit code
              }


              
            void ThreadEntryPoint()
              
            {
                 
            // This is the desired entry-point-function but to get
                 
            // here we have to use a 2 step procedure involving
                 
            // the ThreadStaticEntryPoint() function.

                
            for (int i = loopStart; i <= loopEnd; ++i)
                
            {
                  
            if (i % dispFrequency == 0)
                  
            {
                      printf( 
            "%s: i = %d\n", threadName.c_str(), i );
                  }

                }

                printf( 
            "%s thread terminating\n", threadName.c_str() );
              }

            }
            ;


            int main()
            {
                
            // All processes get a primary thread automatically. This primary
                
            // thread can generate additional threads.  In this program the
                
            // primary thread creates 2 additional threads and all 3 threads
                
            // then run simultaneously without any synchronization.  No data
                
            // is shared between the threads.

                
            // We instantiate an object of the ThreadX class. Next we will
                
            // create a thread and specify that the thread is to begin executing
                
            // the function ThreadEntryPoint() on object o1. Once started,
                
            // this thread will execute until that function terminates or
                
            // until the overall process terminates.

                ThreadX 
            * o1 = new ThreadX( 012000 );

                
            // When developing a multithreaded WIN32-based application with
                
            // Visual C++, you need to use the CRT thread functions to create
                
            // any threads that call CRT functions. Hence to create and terminate
                
            // threads, use _beginthreadex() and _endthreadex() instead of
                
            // the Win32 APIs CreateThread() and EndThread().

                
            // The multithread library LIBCMT.LIB includes the _beginthread()
                
            // and _endthread() functions. The _beginthread() function performs
                
            // initialization without which many C run-time functions will fail.
                
            // You must use _beginthread() instead of CreateThread() in C programs
                
            // built with LIBCMT.LIB if you intend to call C run-time functions.

                
            // Unlike the thread handle returned by _beginthread(), the thread handle
                
            // returned by _beginthreadex() can be used with the synchronization APIs.

                HANDLE   hth1;
                unsigned  uiThread1ID;

                hth1 
            = (HANDLE)_beginthreadex( NULL,         // security
                                               0,            // stack size
                                               ThreadX::ThreadStaticEntryPoint,
                                               o1,           
            // arg list
                                               CREATE_SUSPENDED,  // so we can later call ResumeThread()
                                               &uiThread1ID );

                
            if ( hth1 == 0 )
                    printf(
            "Failed to create thread 1\n");

                DWORD   dwExitCode;

                GetExitCodeThread( hth1, 
            &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
                printf( "initial thread 1 exit code = %u\n", dwExitCode );

                
            // The System::Threading::Thread object in C++/CLI has a "Name" property.
                
            // To create the equivalent functionality in C++ I added a public data member
                
            // named threadName.

                o1
            ->threadName = "t1";

                ThreadX 
            * o2 = new ThreadX( -100000002000 );

                HANDLE   hth2;
                unsigned  uiThread2ID;

                hth2 
            = (HANDLE)_beginthreadex( NULL,         // security
                                               0,            // stack size
                                               ThreadX::ThreadStaticEntryPoint,
                                               o2,           
            // arg list
                                               CREATE_SUSPENDED,  // so we can later call ResumeThread()
                                               &uiThread2ID );

                
            if ( hth2 == 0 )
                    printf(
            "Failed to create thread 2\n");

                GetExitCodeThread( hth2, 
            &dwExitCode );  // should be STILL_ACTIVE = 0x00000103 = 259
                printf( "initial thread 2 exit code = %u\n", dwExitCode );

                o2
            ->threadName = "t2";

                
            // If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()
                
            // we wouldn't now need to call ResumeThread().

                ResumeThread( hth1 );   
            // serves the purpose of Jaeschke's t1->Start()

                ResumeThread( hth2 );

                
            // In C++/CLI the process continues until the last thread exits.
                
            // That is, the thread's have independent lifetimes. Hence
                
            // Jaeschke's original code was designed to show that the primary
                
            // thread could exit and not influence the other threads.

                
            // However in C++ the process terminates when the primary thread exits
                
            // and when the process terminates all its threads are then terminated.
                
            // Hence if you comment out the following waits, the non-primary
                
            // threads will never get a chance to run.

                WaitForSingleObject( hth1, INFINITE );
                WaitForSingleObject( hth2, INFINITE );

                GetExitCodeThread( hth1, 
            &dwExitCode );
                printf( 
            "thread 1 exited with code %u\n", dwExitCode );

                GetExitCodeThread( hth2, 
            &dwExitCode );
                printf( 
            "thread 2 exited with code %u\n", dwExitCode );

                
            // The handle returned by _beginthreadex() has to be closed
                
            // by the caller of _beginthreadex().

                CloseHandle( hth1 );
                CloseHandle( hth2 );

                delete o1;
                o1 
            = NULL;

                delete o2;
                o2 
            = NULL;

                printf(
            "Primary thread terminating.\n");
            }


            二解釋
            1)如果你正在編寫C/C++代碼,決不應(yīng)該調(diào)用CreateThread。相反,應(yīng)該使用VisualC++運(yùn)行期庫函數(shù)_beginthreadex,推出也應(yīng)該使用_endthreadex。如果不使用Microsoft的VisualC++編譯器,你的編譯器供應(yīng)商有它自己的CreateThred替代函數(shù)。不管這個替代函數(shù)是什么,你都必須使用。

            2)因為_beginthreadex和_endthreadex是CRT線程函數(shù),所以必須注意編譯選項runtimelibaray的選擇,使用MT或MTD。

            3) _beginthreadex函數(shù)的參數(shù)列表與CreateThread函數(shù)的參數(shù)列表是相同的,但是參數(shù)名和類型并不完全相同。這是因為Microsoft的C/C++運(yùn)行期庫的開發(fā)小組認(rèn)為,C/C++運(yùn)行期函數(shù)不應(yīng)該對Windows數(shù)據(jù)類型有任何依賴。_beginthreadex函數(shù)也像CreateThread那樣,返回新創(chuàng)建的線程的句柄。
            下面是關(guān)于_beginthreadex的一些要點:
            •每個線程均獲得由C/C++運(yùn)行期庫的堆棧分配的自己的tiddata內(nèi)存結(jié)構(gòu)。(tiddata結(jié)構(gòu)位于Mtdll.h文件中的VisualC++源代碼中)。

            •傳遞給_beginthreadex的線程函數(shù)的地址保存在tiddata內(nèi)存塊中。傳遞給該函數(shù)的參數(shù)也保存在該數(shù)據(jù)塊中。

            •_beginthreadex確實從內(nèi)部調(diào)用CreateThread,因為這是操作系統(tǒng)了解如何創(chuàng)建新線程的唯一方法。

            •當(dāng)調(diào)用CreatetThread時,它被告知通過調(diào)用_threadstartex而不是pfnStartAddr來啟動執(zhí)行新線程。還有,傳遞給線程函數(shù)的參數(shù)是tiddata結(jié)構(gòu)而不是pvParam的地址。

            •如果一切順利,就會像CreateThread那樣返回線程句柄。如果任何操作失敗了,便返回NULL。

            4) _endthreadex的一些要點:
            •C運(yùn)行期庫的_getptd函數(shù)內(nèi)部調(diào)用操作系統(tǒng)的TlsGetValue函數(shù),該函數(shù)負(fù)責(zé)檢索調(diào)用線程的tiddata內(nèi)存塊的地址。

            •然后該數(shù)據(jù)塊被釋放,而操作系統(tǒng)的ExitThread函數(shù)被調(diào)用,以便真正撤消該線程。當(dāng)然,退出代碼要正確地設(shè)置和傳遞。

            5)雖然也提供了簡化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

            6)線程handle因為是內(nèi)核對象,所以需要在最后closehandle。

            7)更多的API:HANDLE GetCurrentProcess();HANDLE GetCurrentThread();DWORD GetCurrentProcessId();DWORD GetCurrentThreadId()。DWORD SetThreadIdealProcessor(HANDLE hThread,DWORD dwIdealProcessor);BOOL SetThreadPriority(HANDLE hThread,int nPriority);BOOL SetPriorityClass(GetCurrentProcess(),  IDLE_PRIORITY_CLASS);BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);BOOL SwitchToThread();

            三注意
            1)C++主線程的終止,同時也會終止所有主線程創(chuàng)建的子線程,不管子線程有沒有執(zhí)行完畢。所以上面的代碼中如果不調(diào)用WaitForSingleObject,則2個子線程t1和t2可能并沒有執(zhí)行完畢或根本沒有執(zhí)行。
            2)如果某線程掛起,然后有調(diào)用WaitForSingleObject等待該線程,就會導(dǎo)致死鎖。所以上面的代碼如果不調(diào)用resumethread,則會死鎖。

            posted on 2007-07-25 13:25 夢在天涯 閱讀(28221) 評論(1)  編輯 收藏 引用 所屬分類: CPlusPlus

            評論

            # re: C++多線程(二) 2007-07-25 14:43 pass86

            關(guān)注  回復(fù)  更多評論   

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計

            • 隨筆 - 461
            • 文章 - 4
            • 評論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1804303
            • 排名 - 5

            最新評論

            閱讀排行榜

            波多野结衣中文字幕久久| 久久久久成人精品无码| 国产亚洲综合久久系列| 久久r热这里有精品视频| 久久精品国产一区二区三区| 欧美粉嫩小泬久久久久久久| 精品久久久久久国产| 91久久精品视频| 久久无码中文字幕东京热| 色综合久久久久网| 国产精品99久久久久久宅男小说| 久久久久久久亚洲Av无码| 国产精品免费看久久久香蕉 | 日本人妻丰满熟妇久久久久久| 久久青草国产精品一区| 人妻无码精品久久亚瑟影视| 久久亚洲高清观看| 久久婷婷五月综合97色一本一本| 国产日韩久久久精品影院首页| 久久久无码精品亚洲日韩按摩| 老司机午夜网站国内精品久久久久久久久 | 人妻丰满?V无码久久不卡| 国内精品久久久久久99| 久久精品国产亚洲AV蜜臀色欲| 国产午夜精品久久久久九九电影| 久久综合香蕉国产蜜臀AV| 久久国产免费直播| 久久久久亚洲精品中文字幕| 久久综合狠狠色综合伊人| 国产综合久久久久久鬼色| 亚洲中文字幕无码久久精品1| 亚洲精品美女久久久久99小说| 国产免费久久精品99久久| 91精品国产综合久久四虎久久无码一级| 亚洲AV乱码久久精品蜜桃| 久久久久久久精品妇女99| 思思久久99热只有频精品66| 久久亚洲AV无码西西人体| 久久国产精品免费| 欧美国产成人久久精品| 亚洲国产成人精品无码久久久久久综合 |