• <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++ 高級(jí)} {C#界面,C++核心算法} {設(shè)計(jì)模式} {C#基礎(chǔ)}

            C++多線程(二)

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

            一 簡單實(shí)例(來自codeprojct:http://www.codeproject.com/useritems/MultithreadingTutorial.asp
            主線程創(chuàng)建2個(gè)線程t1和t2,創(chuàng)建時(shí)2個(gè)線程就被掛起,后來調(diào)用ResumeThread恢復(fù)2個(gè)線程,是其開始執(zhí)行,調(diào)用WaitForSingleObject等待2個(gè)線程執(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ù)。不管這個(gè)替代函數(shù)是什么,你都必須使用。

            2)因?yàn)開beginthreadex和_endthreadex是CRT線程函數(shù),所以必須注意編譯選項(xiàng)runtimelibaray的選擇,使用MT或MTD。

            3) _beginthreadex函數(shù)的參數(shù)列表與CreateThread函數(shù)的參數(shù)列表是相同的,但是參數(shù)名和類型并不完全相同。這是因?yàn)镸icrosoft的C/C++運(yùn)行期庫的開發(fā)小組認(rèn)為,C/C++運(yùn)行期函數(shù)不應(yīng)該對(duì)Windows數(shù)據(jù)類型有任何依賴。_beginthreadex函數(shù)也像CreateThread那樣,返回新創(chuàng)建的線程的句柄。
            下面是關(guān)于_beginthreadex的一些要點(diǎn):
            •每個(gè)線程均獲得由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確實(shí)從內(nèi)部調(diào)用CreateThread,因?yàn)檫@是操作系統(tǒng)了解如何創(chuàng)建新線程的唯一方法。

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

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

            4) _endthreadex的一些要點(diǎn):
            •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因?yàn)槭莾?nèi)核對(duì)象,所以需要在最后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++主線程的終止,同時(shí)也會(huì)終止所有主線程創(chuàng)建的子線程,不管子線程有沒有執(zhí)行完畢。所以上面的代碼中如果不調(diào)用WaitForSingleObject,則2個(gè)子線程t1和t2可能并沒有執(zhí)行完畢或根本沒有執(zhí)行。
            2)如果某線程掛起,然后有調(diào)用WaitForSingleObject等待該線程,就會(huì)導(dǎo)致死鎖。所以上面的代碼如果不調(diào)用resumethread,則會(huì)死鎖。

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

            評(píng)論

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

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

            公告

            EMail:itech001#126.com

            導(dǎo)航

            統(tǒng)計(jì)

            • 隨筆 - 461
            • 文章 - 4
            • 評(píng)論 - 746
            • 引用 - 0

            常用鏈接

            隨筆分類

            隨筆檔案

            收藏夾

            Blogs

            c#(csharp)

            C++(cpp)

            Enlish

            Forums(bbs)

            My self

            Often go

            Useful Webs

            Xml/Uml/html

            搜索

            •  

            積分與排名

            • 積分 - 1804430
            • 排名 - 5

            最新評(píng)論

            閱讀排行榜

            四虎影视久久久免费观看| 中文成人无码精品久久久不卡 | 94久久国产乱子伦精品免费 | 久久国产成人精品麻豆| 四虎国产精品成人免费久久| 久久国产综合精品五月天| 久久综合九色综合欧美狠狠| 2021久久国自产拍精品| 人妻少妇久久中文字幕| 亚洲AV无码久久寂寞少妇| 久久国语露脸国产精品电影| 99久久综合国产精品免费| 四虎国产精品成人免费久久| 久久久噜噜噜久久中文字幕色伊伊| 亚洲精品tv久久久久久久久久| 久久93精品国产91久久综合| 国产激情久久久久影院老熟女| 国产精品久久久天天影视香蕉| 99久久国产亚洲高清观看2024 | 久久久99精品一区二区| 久久精品成人免费国产片小草| 国产AⅤ精品一区二区三区久久| 国产成人综合久久精品尤物| 久久se这里只有精品| 无码人妻少妇久久中文字幕| 久久香综合精品久久伊人| 亚洲国产精品无码久久久秋霞2| 久久亚洲AV成人出白浆无码国产 | 久久精品国产亚洲精品| 最新久久免费视频| 久久久无码一区二区三区| 伊人久久精品线影院| 久久人人爽人爽人人爽av| 久久久无码精品亚洲日韩蜜臀浪潮| 香蕉久久av一区二区三区| 久久91综合国产91久久精品| 久久精品无码一区二区日韩AV| 久久丫忘忧草产品| 国产亚洲色婷婷久久99精品91| 精品国产日韩久久亚洲| 久久这里只有精品久久|