• <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>

            Kisser Leon

            這個kisser不太冷
            posts - 100, comments - 102, trackbacks - 0, articles - 0

            #include <stdio.h>
            #include <windows.h>

            const int numThreads = 3;

            ?

            DWORD WINAPI helloFunc(LPVOID pArg)

            {

            ?????? int num = (int) pArg;

            ?????? printf("Hello Thread %d\n", num);

            ??????

            ?????? return 0;

            }

            ?

            int main()

            {?????

            ?????? HANDLE hThread[numThreads];

            ?

            ?????? for (int i = 0; i < numThreads; i++)

            ?????? {

            ????????????? hThread[i] = CreateThread(NULL, 0, helloFunc, (LPVOID)i, 0, NULL);

            ?????? }

            ?

            ?????? WaitForMultipleObjects(numThreads, hThread, TRUE, INFINITE);

            ?

            ?????? return 0;

            }

            ?

            上面可以說是一個最簡單的多線程程序了。

            運(yùn)行時庫選項(xiàng):

            (1) ????? 單線程調(diào)試 (/MLd)

            (2) ????? 多線程調(diào)試 DLL (/MDd)

            (3) ????? 多線程調(diào)試 (/MTd)

            上面三個是 debug 版本的,還有與它們相對的三個 release 版本等。

            由于一開始的時候系統(tǒng)默認(rèn)的是 /MLd ,所以產(chǎn)生一些很有意思的問題,比如說有些線程 的線程函數(shù)會被執(zhí)行多次:

            Hello Thread 1

            Hello Thread 1

            Hello Thread 0

            Hello Thread 2

            Press any key to continue

            線程 1 被執(zhí)行了兩次!

            Hello Thread 0

            Hello Thread Hello Thread 1

            Hello Thread Hello Thread 1

            2

            Press any key to continue

            這個就更奇怪了!雖然是因?yàn)橛?/span> race condition 在,但是為什么會多出一個 Hello Thread 呢( 5 Hello Thread 4 個數(shù)字)?那就只有一個原因,有一個數(shù)字被覆蓋了(難道會有可能沒來得及輸出嗎?)!

            Intel Thread Checker 進(jìn)行 check 的時候,會發(fā)生下面這樣的問題,甚是奇怪!

            圖片傳不上來。下次再傳。終于上傳成功了,娃哈哈
            P1.bmp


            碰到這么多問題,因?yàn)榕际浅鯇W(xué)者,所以就一直沒有察覺出來編譯選項(xiàng)設(shè)置有問題。而且我一直覺得都是對的。只是對其中的一個線程的線程函數(shù)為什么會執(zhí)行兩遍感覺很
            confuse WHY WHY WHY Google 一個線程的線程函數(shù)是否可以執(zhí)行兩遍,找不到有用的咚咚! Baidu 也沒有相關(guān)信息。哭。只能暫時放棄,不過我始終還是不明白一個線程的線程函數(shù)為什么可以執(zhí)行多次?我也沒有見過這樣的例子。可能這個問題在俺腦子里走太多路了,今天突發(fā)奇想,會不會是編譯選項(xiàng)有問題?檢查了一下才發(fā)現(xiàn)原來一開始忘了把它設(shè)為多線程的了,設(shè)回來之后就一切正常了,試了 N 多次都沒有碰到過問題(雖然這不能證明肯定沒有問題!線程執(zhí)行順序是不可預(yù)料的!要看 CPU 的心情的, J )。

            ?

            Next, 接下來查一下編譯器相關(guān)資料。

            Multithreaded Libraries Performance?

            The single-threaded CRT is no longer in vs2005 available. This topic discusses how to get the maximum performance from the multithreaded libraries.

            The performance of the multithreaded libraries has been improved and is close to the performance of the now-eliminated single-threaded libraries. For those situations when even higher performance is required, there are several new features.

            ·???????? Independent stream locking allows you to lock a stream and then use _nolock Functions that access the stream directly. This allows lock usage to be hoisted outside critical loops.

            ·???????? Per-thread locale reduces the cost of locale access for multithreaded scenarios (see _configthreadlocale).

            ·???????? Locale-dependent functions (with names ending in _l) take the locale as a parameter, removing substantial cost (for example, printf, _printf_l, wprintf, _wprintf_l).

            ·???????? Optimizations for common codepages reduce the cost of many short operations.

            ·???????? Defining _CRT_DISABLE_PERFCRIT_LOCKS forces all I/O operations to assume a single-threaded I/O model and use the _nolock forms of the functions. This allows highly I/O-based single-threaded applications to get better performance.

            ·???????? Exposure of the CRT heap handle allows you to enable the Windows Low Fragmentation Heap (LFH) for the CRT heap, which can substantially improve performance in highly scaled scenarios.

            ?

            運(yùn)行時庫是程序在運(yùn)行時所需要的庫文件 ,通常運(yùn)行時庫是以 LIB DLL 形式提供的。 C 運(yùn)行時庫誕生于 20 世紀(jì) 70 年代,當(dāng)時的程序世界還很單純,應(yīng)用程序都是單線程的,多任務(wù)或多線程機(jī)制在此時還屬于新觀念。所以這個時期的 C 運(yùn)行時庫都是單線程的。

            隨著操作系統(tǒng)多線程技術(shù)的發(fā)展,最初的 C 運(yùn)行時庫無法滿足程序的需求,出現(xiàn)了嚴(yán)重的問題。 C 運(yùn)行時庫使用了多個全局變量(例如 errno )和靜態(tài)變量,這可能在多線程程序中引起沖突。假設(shè)兩個線程都同時設(shè)置 errno ,其結(jié)果是后設(shè)置的 errno 會將先前的覆蓋,用戶得不到正確的錯誤信息。

              因此, Visual C++ 提供了兩種版本的 C 運(yùn)行時庫。一個版本供單線程應(yīng)用程序調(diào)用,另一個版本供多線程應(yīng)用程序調(diào)用。多線程運(yùn)行時庫與單線程運(yùn)行時庫有兩個重大差別:
              ( 1 )類似 errno 的全局變量,每個線程單獨(dú)設(shè)置一個。這樣從每個線程中可以獲取正確的錯誤信息。
              ( 2 )多線程庫中的數(shù)據(jù)結(jié)構(gòu)以同步機(jī)制加以保護(hù)。這樣可以避免訪問時候的沖突。

               Visual C++ 提供的多線程運(yùn)行時庫又分為靜態(tài)鏈接庫和動態(tài)鏈接庫兩類,而每一類運(yùn)行時庫又可再分為 debug 版和 release 版,因此 Visual C++ 共提供了 6 個運(yùn)行時庫。如下表:

            C 運(yùn)行時庫

            庫文件

            Single thread(static link) ML

            libc.lib

            Debug single thread(static link) MLd

            libcd.lib

            MultiThread(static link) ?MT

            libcmt.lib

            Debug multiThread(static link) MTd

            libcmtd.lib

            MultiThread(dynamic link) MD

            msvert.lib

            Debug multiThread(dynamic link) MDd

            msvertd.lib


               2.C 運(yùn)行時庫的作用
               C 運(yùn)行時庫除了給我們提供必要的庫函數(shù)調(diào)用(如 memcpy printf malloc 等)之外,它提供的另一個最重要的功能是為應(yīng)用程序添加啟動函數(shù)。
               C 運(yùn)行時庫啟動函數(shù)的主要功能為進(jìn)行程序的初始化,對全局變量進(jìn)行賦初值,加載用戶程序的入口函數(shù)。
              不采用寬字符集的控制臺程序的入口點(diǎn)為 mainCRTStartup(void) 。下面我們以該函數(shù)為例來分析運(yùn)行時庫究竟為我們添加了怎樣的入口程序。這個函數(shù)在 crt0.c 中被定義,下列的代碼經(jīng)過了筆者的整理和簡化:

            void mainCRTStartup(void)
            {
              int mainret;
              /* 獲得 WIN32 完整的版本信息 */
              _osver = GetVersion();
              _winminor = (_osver >> 8) & 0x00FF ;
              _winmajor = _osver & 0x00FF ;
              _winver = (_winmajor << 8) + _winminor;
              _osver = (_osver >> 16) & 0x00FFFF ;

              _ioinit(); /* initialize lowio */

              /* 獲得命令行信息 */
              _acmdln = (char *) GetCommandLineA();

              /* 獲得環(huán)境信息 */
              _aenvptr = (char *) __crtGetEnvironmentStringsA();

              _setargv(); /* 設(shè)置命令行參數(shù) */
              _setenvp(); /* 設(shè)置環(huán)境參數(shù) */

              _cinit(); /* C 數(shù)據(jù)初始化:全局變量初始化,就在這里! */

              __initenv = _environ;
              mainret = main( __argc, __argv, _environ ); /* 調(diào)用 main 函數(shù) */

              exit( mainret );
            }

            從以上代碼可知,運(yùn)行庫在調(diào)用用戶程序的 main WinMain 函數(shù)之前,進(jìn)行了一些初始化工作。初始化完成后,接著才調(diào)用了我們編寫的 main WinMain 函數(shù)。只有這樣,我們的 C 語言運(yùn)行時庫和應(yīng)用程序才能正常地工作起來。

              除了 crt0.c 外, C 運(yùn)行時庫中還包含 wcrt0.c wincrt0.c wwincrt0.c 三個文件用來提供初始化函數(shù)。 wcrt0.c crt0.c 的寬字符集版, wincrt0.c 中包含 windows 應(yīng)用程序的入口函數(shù),而 wwincrt0.c 則是 wincrt0.c 的寬字符集版。

               Visual C++ 的運(yùn)行時庫源代碼缺省情況下不被安裝。如果您想查看其源代碼,則需要重裝 Visual C++ ,并在重裝在時選中安裝運(yùn)行庫源代碼選項(xiàng)。

            3.
            各種 C 運(yùn)行時庫的區(qū)別

              ( 1 )靜態(tài)鏈接的單線程庫
              靜態(tài)鏈接的單線程庫只能用于單線程的應(yīng)用程序 C 運(yùn)行時庫的目標(biāo)代碼最終被編譯在應(yīng)用程序的二進(jìn)制文件中。通過 /ML 編譯選項(xiàng)可以設(shè)置 Visual C++ 使用靜態(tài)鏈接的單線程庫。

              ( 2 )靜態(tài)鏈接的多線程庫
              靜態(tài)鏈接的多線程庫的目標(biāo)代碼也最終被編譯在應(yīng)用程序的二進(jìn)制文件中,但是它可以在多線程程序中使用。通過 /MT 編譯選項(xiàng)可以設(shè)置 Visual C++ 使用靜態(tài)鏈接的單線程庫。

              ( 3 )動態(tài)鏈接的運(yùn)行時庫
              動態(tài)鏈接的運(yùn)行時庫將所有的 C 庫函數(shù)保存在一個單獨(dú)的動態(tài)鏈接庫 MSVCRTxx.DLL 中, MSVCRTxx.DLL 處理了多線程問題。使用 /MD 編譯選項(xiàng)可以設(shè)置 Visual C++ 使用動態(tài)鏈接的運(yùn)行時庫。

               /MDd /MLd /MTd 選項(xiàng)使用 Debug runtime library( 調(diào)試版本的運(yùn)行時刻函數(shù)庫 ) ,與 /MD /ML /MT 分別對應(yīng)。 Debug 版本的 Runtime Library 包含了調(diào)試信息,并采用了一些保護(hù)機(jī)制以幫助發(fā)現(xiàn)錯誤,加強(qiáng)了對錯誤的檢測,因此在運(yùn)行性能方面比不上 Release 版本。

              下面看一個未正確使用 C 運(yùn)行時庫的控制臺程序

            #include <stdio.h>
            #include <afx.h>
            int main()
            {
              CFile file;
              CString str("I love you");
              TRY
              {
               file.Open("file.dat",CFile::modeWrite | CFile::modeCreate);
              }
              CATCH( CFileException, e )
              {
               #ifdef _DEBUG
               afxDump << "File could not be opened " << e->m_cause << "\n";
               #endif
              }
              END_CATCH

              file.Write(str,str.GetLength());
              file.Close();
            }

            我們在 "rebuild all" 的時候發(fā)生了 link 錯誤:

            nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
            nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
            main.exe : fatal error LNK1120: 2 unresolved externals
            Error executing cl.exe.

            發(fā)生錯誤的原因在于 Visual C++ 對控制臺程序默認(rèn)使用單線程的靜態(tài)鏈接庫,而 MFC 中的 CFile 類已暗藏了多線程。我們只需要在 Visual C++6.0 中依次點(diǎn)選 Project->Settings->C/C++ 菜單和選項(xiàng),在 Project Options 里修改編譯選項(xiàng)即可。

            不過最上面的那個程序在 6.0里面是可以運(yùn)行的,現(xiàn)象同2003的是一樣的。
            ***********************************************

            ?

            從字面上看,運(yùn)行庫是程序在運(yùn)行時所需要的庫文件。通常運(yùn)行庫是以 DLL 形式提供的。 Delphi C++ Builder 的運(yùn)行庫為 .bpl 文件,實(shí)際還是一個 DLL 。運(yùn)行庫中一般包括編程時常用的函數(shù),如字符串操作、文件操作、界面等內(nèi)容。不同的語言所支持的函數(shù)通常是不同的,所以使用的庫也是完全不同的,這就是為什么有 VB 運(yùn)行庫、 C 運(yùn)行庫、 Delphi 運(yùn)行庫之分的原因。即使都是 C++ 語言,也可能因?yàn)樘峁┑暮瘮?shù)不同,而使用不同的庫。如 VC++ 使用的運(yùn)行庫和 C++ Builder 就完全不同。

            如果不使用運(yùn)行庫,每個程序中都會包括很多重復(fù)的代碼,而使用運(yùn)行庫,可以大大縮小編譯后的程序的大小。但另一方面,由于使用了運(yùn)行庫,所以在分發(fā)程序時就必須帶有這些庫,比較麻煩。如果在操作系統(tǒng)中找不到相應(yīng)的運(yùn)行庫程序就無法運(yùn)行。為了解決這個矛盾, Windows 總是會帶上它自己開發(fā)的軟件的最新的運(yùn)行庫。象 Windows 2000 以后的版本都包括 Visual Basic 5.0/6.0 的庫。 Internet Explorer 總是帶有最新的 Visual C++ 6.0 的庫。 Windows XP 帶有 Microsoft .NET 1.0 (用于 VB.NET C# )的庫。 Visual C++ Delphi C++ Builder 允許用戶選擇所編譯得到的程序是否依賴于運(yùn)行庫。而 VB FoxPro PowerBuilder LabWindows/CVI Matlab 就不允許用戶進(jìn)行這種選擇,必須依賴于運(yùn)行庫。

            ?

            小結(jié)

            看了上面這么多咚咚以后(我估計沒幾個人會有這個耐心把這么多東西看完的,娃哈哈),不過我還是把它完整地看完了,中間那一段是抄的,講得很好,講得非常清楚。嗯。有一點(diǎn)是可以肯定的,那就是不要用 ML 單線程版本,況且 2005 已經(jīng)不支持 ML (注意,這里 ML 不是 Make L*ve 的縮寫,汗!)了。另外, ML 不支持多線程的,所以如果使用 ML 來編譯運(yùn)行的話,肯定會出很多問題的,雖然它沒有明確說出會發(fā)生什么樣的問題。

            一個困擾偶很長時間的問題終于解決。把 MLd 改為 MDd 所有問題就都解決了,用 Intel Thread Checker check 了一下也沒問題。如果大家有碰到同樣的問題的話,希望以上能夠給你一點(diǎn)有用的信息。有啥問題,歡迎與我聯(lián)系。有啥說的不對的,請批評指正。恩。

            Have fun.

            Feedback

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-03-27 21:36 by 小熊
            晚上傳了n多次圖片,都沒有成功,哭
            CSDN一次就pass了。sigh

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-03-28 12:52 by 小熊
            線程函數(shù)結(jié)束,線程就結(jié)束

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題 [未登錄]  回復(fù)  更多評論   

            2007-03-30 09:27 by hdqqq
            hThread[i] = CreateThread(NULL, 0, helloFunc, (LPVOID)i, 0, NULL);
            上面這句是有問題的,因?yàn)镃reateThread返回時候,并不保證線程已經(jīng)啟動了,所以進(jìn)入下一個循環(huán)后i就被修改,導(dǎo)致線程取得了錯誤的參數(shù).

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-03-30 09:34 by 小熊
            但是一個線程函數(shù)不可能被執(zhí)行多次的。呵呵

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-03-30 13:31 by think
            這樣寫倒是吃驚:(LPVOID)i
            你的程序在我機(jī)子上沒有問題,也從來不遇到過

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-03-30 17:16 by 小熊
            (LPVOID)i是沒問題的
            你可以把i理解為是一個指針之類的。。。

            在你的機(jī)子上沒問題的原因很可能是,你的運(yùn)行時庫設(shè)置為MD或者M(jìn)T了,那肯定沒問題。如果你設(shè)置為ML的話,肯定會有問題的,呵呵,或者說多運(yùn)行幾次。

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題 [未登錄]  回復(fù)  更多評論   

            2007-04-05 09:16 by christanxw
            本質(zhì)原因是你在線程中使用了printf()這樣的非多線程安全的函數(shù)。你用它的多線程版本(/MTd或/MDd)就沒問題了,或者你在使用/MLd時對printf加鎖也不會出問題。

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2007-04-05 21:44 by 小熊
            恩。不過printf()也不可能讓一個線程函數(shù)執(zhí)行多次的吧?
            使用了多線程版本后,printf()確實(shí)是不會有問題了。恩

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2008-10-09 17:11 by 5871
            很不明白,.....

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題   回復(fù)  更多評論   

            2009-01-20 17:49 by sak
            你這個人很有意思,哇哈哈
            咚咚嗆cei cei 嗆

            # re: 多線程學(xué)習(xí)中碰到的一個很有意思的問題 [未登錄]  回復(fù)  更多評論   

            2010-04-13 20:07 by Leon
            這兩天我也在做操作系統(tǒng)里多線程的實(shí)驗(yàn),這方面的程序確實(shí)錯得讓人匪夷所思,我那還有一個關(guān)于多線程的實(shí)驗(yàn),還有相關(guān)的錯誤總結(jié),你如果想看的話愿意和你分享!
            QQ:250575616
            无夜精品久久久久久| 久久久精品国产sm调教网站| 久久久噜噜噜www成人网| 日本精品久久久久久久久免费| 国产69精品久久久久9999| 69国产成人综合久久精品| 久久不见久久见免费视频7| 久久精品无码专区免费青青| 久久99国产精品尤物| 蜜臀av性久久久久蜜臀aⅴ麻豆| 亚洲中文字幕无码久久综合网 | 亚洲精品99久久久久中文字幕| 91精品国产综合久久香蕉| 久久精品麻豆日日躁夜夜躁| 精品国际久久久久999波多野| 国产午夜免费高清久久影院| 久久福利青草精品资源站| 亚洲一本综合久久| 久久综合视频网站| 亚洲综合熟女久久久30p| 精品久久久久久亚洲| 久久精品一区二区影院| 久久精品桃花综合| 久久国产精品一国产精品金尊| 狠狠色噜噜狠狠狠狠狠色综合久久 | 久久精品国产99久久久香蕉| 亚洲国产成人久久综合野外| 久久久久亚洲AV无码专区首JN| 久久精品国产亚洲av麻豆色欲| 色综合久久天天综合| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区 | 久久精品国产亚洲AV香蕉| 久久久久久久久久久久中文字幕 | 久久综合精品国产二区无码| 久久国产精品77777| 国产真实乱对白精彩久久| 伊人久久国产免费观看视频| 色欲久久久天天天综合网| 狠狠色丁香婷婷综合久久来来去 | 色婷婷久久久SWAG精品| 久久精品毛片免费观看|