青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

道。道。道

安全特性不等于安全的特性

   :: 首頁 :: 聯系 :: 聚合  :: 管理

常用鏈接

搜索

  •  

最新評論

CreateThread 是一個Win 32API 函數,_beginthread 是一個CRT(C Run-Time)函數,他們都是實現多線城的創建的函數,而且他們擁有相同的使用方法,相同的參數列表。

但是他們有什么區別呢?

一般來說,從使用角度是沒有多大的區別的,CRT函數中除了signal()函數不能在CreateThread創建的線城中使用外,其他的CRT函數都可一正常使用,但是如果在CreateThread創建的線城中使用CRT函數的話,會產生一些Memory Leak.

下面是摘自KB的原話:

SUMMARY

All C Run-time functions except the signal() function work correctly when used in threads created by the CreateThread() function. However, depending on what CRT functions are called, there may be a small memory leak when threads are terminated. Calling strlen(), for example, does not trigger the allocation of the CRT thread data-block, and calling malloc(), fopen(), _open(), strtok(), ctime(), or localtime() causes allocation of a CRT per-thread data-block, which may cause a memory leak.

MORE INFORMATION

The "Programming Techniques" manual supplied with Visual C++ 32-bit Edition states that using CreateThread() in a program that uses Libcmt.lib causes many CRT functions to fail. Actually, the only function that should not be used in a thread created with CreateThread() is the signal() function.

There are two ways to create threads. One method involves using the CRT _beginthread() or _beginthreadex() (with Visual C++ 2.0 and later); the other method involves using the CreateThread() API. All CRT functions other than the signal() function work correctly in threads created with either _beginthread() or CreateThread(). However, there are some problems involved with using CRT functions in threads created with CreateThread().

Threads that are created and terminated with the CreateThread() and ExitThread() Win32 API functions do not have memory that is allocated by the CRT for static data and static buffers cleaned up when the thread terminates. Some examples of this type of memory are static data for errno and _doserrno and the static buffers used by functions such as asctime(), ctime(), localtime(), gmtime(), and mktime(). Using CreateThread() in a program that uses the CRT (for example, links with LIBCMT.LIB) may cause a memory leak of about 70-80 bytes each time a thread is terminated.

To guarantee that all static data and static buffers allocated by the CRT are cleaned up when the thread terminates, _beginthreadex() and _endthreadex() should be used when creating a thread. The _beginthreadex() function includes the same parameters and functionality as CreateThread().
另外有個小小的測驗:
?用CreateThread 創建的線城能否被CRT函數 _endthreadex() 關閉?
?
?
CreateThread()和_beginthreadex()在Jeffrey的《Windows核心編程》中講的很清楚,應當盡量避免使用CreateThread()。
事實上,_beginthreadex()在內部先為線程創建一個線程特有的tiddata結構,然后調用CreateThread()。在某些非線程安全的CRT函數中會請求這個結構。如果直接使用CreateThread()的話,那些函數發現請求的tiddata為NULL,就會在現場為該線程創建該結構,此后調用EndThread()時會引起內存泄漏。_endthreadex()可以釋放由CreateThread()創建的線程,實際上,在它的內部會先釋放由_beginthreadex()創建的tiddata結構,然后調用EndThread()。
因此,應當使用_beginthreadex()和_endthreadex(),而避免使用CreateThread()和EndThread()。當然,_beginthread()和_endthread()也是應當避免使用的。
?
?
程序員對于Windows程序中應該用_beginthread還是CreateThread來創建線程,一直有所爭論。本文將從對CRT源代碼出發探討這個問題。

I. 起因

今天一個朋友問我程序中究竟應該使用_beginthread還是CreateThread,并且告訴我如果使用不當可能會有內存泄漏。其實我過去對這個問題也是一知半解,為了對朋友負責,專門翻閱了一下VC的運行庫(CRT)源代碼,終于找到了答案。

II. CRT

CRT(C/C++ Runtime Library)是支持C/C++運行的一系列函數和代碼的總稱。雖然沒有一個很精確的定義,但是可以知道,你的main就是它負責調用的,你平時調用的諸如strlen、strtok、time、atoi之類的函數也是它提供的。我們以Microsoft Visual.NET 2003中所附帶的CRT為例。假設你的.NET 2003安裝在C:Program FilesMicrosoft Visual Studio .NET 2003中,那么CRT的源代碼就在C:Program FilesMicrosoft Visual Studio .NET 2003Vc7crtsrc中。既然有了這些實現的源代碼,我們就可以找到一切解釋了。

III. _beginthread/_endthread

這個函數究竟做了什么呢?它的代碼在thread.c中。閱讀代碼,可以看到它最終也是通過CreateThread來創建線程的,主要區別在于,它先分配了一個_tiddata,并且調用了_initptd來初始化這個分配了的指針。而這個指針最后會被傳遞到CRT的線程包裝函數_threadstart中,在那里會把這個指針作為一個TLS(Thread Local Storage)保存起來。然后_threadstart會調用我們傳入的線程函數,并且在那個函數退出后調用_endthread。這里也可以看到,_threadstart用一個__try/__except塊把我們的函數包了起來,并且在發生異常的時候,調用exit退出。(_threadstart和endthread的代碼都在thread.c中)
這個_tiddata是一個什么樣的結構呢?它在mtdll.h中定義,它的成員被很多CRT函數所用到,譬如int _terrno,這是這個線程中的錯誤標志;char* _token,strtok以來這個變量記錄跨函數調用的信息,...。
那么_endthread又做了些什么呢?除了調用浮點的清除代碼以外,它還調用了_freeptd來釋放和這個線程相關的tiddata。也就是說,在_beginthread里面分配的這塊內存,以及在線程運行過程中其它CRT函數中分配并且記錄在這個內存結構中的內存,在這里被釋放了。
通過上面的代碼,我們可以看到,如果我使用_beginthread函數創建了線程,它會為我創建好CRT函數需要的一切,并且最后無需我操心,就可以把清除工作做得很好,可能唯一需要注意的就是,如果需要提前終止線程,最好是調用_endthread或者是返回,而不要調用ExitThread,因為這可能造成內存釋放不完全。同時我們也可以看出,如果我們用CreateThread函數創建了線程,并且不對C運行庫進行調用(包括任何間接調用),就不必擔心什么問題了。

IV. CreateThread和CRT

或許有人會說,我用CreateThread創建線程以后,我也調用了C運行庫函數,并且也使用ExitThread退出了,可是我的程序運行得好好的,既沒有因為CRT沒有初始化而崩潰,也沒有因為忘記調用_endthread而發生內存泄漏,這是為什么呢,讓我們繼續我們的CRT之旅。
假設我用CreateThread創建了一個線程,我調用strtok函數來進行字符串處理,這個函數肯定是需要某些額外的運行時支持的。strtok的源代碼在strtok.c中。從代碼可見,在多線程情況下,strtok的第一句有效代碼就是_ptiddata ptd = _getptd(),它通過這個來獲得當前的ptd。可是我們并沒有通過_beginthread來創建ptd,那么一定是_getptd搗鬼了。打開tidtable.c,可以看到_getptd的實現,果然,它先嘗試獲得當前的ptd,如果不能,就重新創建一個,因此,后續的CRT調用就安全了。可是這塊ptd最終又是誰釋放的呢?打開dllcrt0.c,可以看到一個DllMain函數。在VC中,CRT既可以作為一個動態鏈接庫和主程序鏈接,也可以作為一個靜態庫和主程序鏈接,這個在Project Setting->Code Generations里面可以選。當CRT作為DLL鏈接到主程序時,DllMain就是CRT DLL的入口。Windows的DllMain可以由四種原因調用:Process Attach/Process Detach/Thread Attach/Thread Detach,最后一個,也就是當線程函數退出后但是線程還沒有銷毀前,會在這個線程的上下文中用Thread Detach調用DllMain,這里,CRT做了一個_freeptd(NULL),也就是說,如果有ptd,就free掉。所以說,恰巧沒有發生內存泄漏是因為你用的是動態鏈接的CRT。
于是我們得出了一個更精確的結論,如果我沒有使用那些會使用_getptd的CRT函數,使用CreateThread就是安全的。

V. 使用ptd的函數

那么,究竟那些函數使用了_getptd呢?很多!在CRT目錄下搜索_getptd,你會發覺很多意想不到的函數都用到了它,除了strtok、rand這類需要保持狀態的,還有所有的字符串相關函數,因為它們要用到ptd中的locale信息;所有的mbcs函數,因為它們要用到ptd中的mbcs信息,...。

VI. 測試代碼

下面是一段測試代碼(leaker中用到了atoi,它需要ptd):

#include
#include
#include
#include

volatile bool threadStarted = false;

void leaker()
{
??? std::cout << atoi( "0" ) << std::endl;
}

DWORD __stdcall CreateThreadFunc( LPVOID )
{
??? leaker();
??? threadStarted = false;
??? return 0;
}

DWORD __stdcall CreateThreadFuncWithEndThread( LPVOID )
{
??? leaker();
??? threadStarted = false;
??? _endthread();
??? return 0;
}

void __cdecl beginThreadFunc( LPVOID )
{
??? leaker();
??? threadStarted = false;
}

int main()
{
??? for(;;)
??? {
??????? while( threadStarted )
??????????? Sleep( 5 );
??????? threadStarted = true;
//????? _beginthread( beginThreadFunc, 0, 0 );//1
??????? CreateThread( NULL, 0, CreateThreadFunc, 0, 0, 0 );//2
//????? CreateThread( NULL, 0, CreateThreadFuncWithEndThread, 0, 0, 0 );//3
??? }
??? return 0;
}

如果你用VC的多線程+靜態鏈接CRT選項去編譯這個程序,并且嘗試打開1、2、3之中的一行,你會發覺只有2打開的情況下,程序才會發生內存泄漏(可以在Task Manager里面明顯的觀察到)。3之所以不會出現內存泄漏是因為主動調用了_endthread。

VII. 總結

如果你使用了DLL方式鏈接的CRT庫,或者你只是一次性創建少量的線程,那么你或許可以采取鴕鳥策略,忽視這個問題。上面一節代碼中第3種方法基于對CRT庫的了解,但是并不保證這是一個好的方法,因為每一個版本的VC的CRT可能都會有些改變。看來,除非你的頭腦清晰到可以記住這一切,或者你可以不厭其煩的每調用一個C函數都查一下CRT代碼,否則總是使用_beginthread(或者它的兄弟_beginthreadex)是一個不錯的選擇。

[后記]
網友condor指出本文的一個錯誤:在dllcrt0.c中,DllMain的Thread Detach所釋放的ptd,其實是dllcrt0.c的DllMain中的Thread Attach所創建的。也就是說,當你用CRT DLL的時候,DllMain對線程做了一切初始化/清除工作。我查看源代碼,thread.c中的_threadstart函數,在設置TLS之前做了檢查,這其實就是為了避免重復設置導致的內存泄漏。

posted on 2006-11-25 00:51 獨孤九劍 閱讀(5169) 評論(0)  編輯 收藏 引用 所屬分類: Win32Visual C++ 8.0
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            中文一区在线| 欧美96在线丨欧| 欧美精品国产一区| 亚洲毛片视频| 午夜精品久久久久久久99樱桃 | 久久精品视频在线观看| 香蕉亚洲视频| 亚洲一区区二区| 一区二区三区四区国产精品| 亚洲欧美日韩国产一区二区| 午夜精品成人在线| 久久黄色网页| 免费看黄裸体一级大秀欧美| 欧美激情免费在线| 国产精品视区| 亚洲国产精品小视频| 中文在线资源观看网站视频免费不卡 | 黄色成人片子| 日韩视频精品在线| 欧美在线播放视频| 亚洲国产精品久久久久久女王| 亚洲福利视频三区| 亚洲综合色在线| 免费久久99精品国产自| 国产精品扒开腿做爽爽爽软件| 国产性做久久久久久| 日韩亚洲国产精品| 久久中文字幕一区二区三区| 日韩视频免费| 美女黄网久久| 国产亚洲欧美激情| 亚洲午夜91| 亚洲第一主播视频| 久久精品国产免费| 国产精品人人做人人爽人人添| 最新高清无码专区| 久久天天躁夜夜躁狠狠躁2022| 亚洲精品一区二区三区99| 久久精品视频在线| 国产女人18毛片水18精品| 一区二区精品国产| 91久久精品国产91久久| 久久精品视频亚洲| 国产日韩欧美一区在线 | 亚洲欧洲av一区二区| 日韩写真在线| 欧美96在线丨欧| 亚洲欧美一区二区精品久久久| 欧美精品一卡二卡| 亚洲国产精品美女| 免播放器亚洲| 久久爱www久久做| 国产女主播一区二区| 亚洲欧美日韩区| 一区二区三区欧美激情| 欧美美女日韩| 亚洲视屏在线播放| 日韩性生活视频| 国产精品二区在线| 亚洲男人的天堂在线| 亚洲深夜av| 国产欧美日韩亚洲一区二区三区 | 亚洲视频在线免费观看| 亚洲日本中文字幕| 欧美精品少妇一区二区三区| 亚洲精品在线观| 亚洲欧洲在线播放| 欧美精品久久99| 亚洲视频国产视频| 9l视频自拍蝌蚪9l视频成人| 欧美日韩一区二区三区四区在线观看| 亚洲美女福利视频网站| 亚洲人成网站在线观看播放| 欧美日韩精品综合在线| 亚洲免费婷婷| 午夜在线视频观看日韩17c| 国产日韩欧美精品一区| 麻豆成人在线| 欧美精品一区二区视频| 午夜精品福利视频| 欧美在线亚洲一区| 亚洲精品国产精品国自产在线| 亚洲精品久久久久久下一站| 欧美日韩麻豆| 久久亚洲精品一区| 欧美成人自拍| 亚洲欧美另类久久久精品2019| 亚洲欧美日韩国产成人| 亚洲国产日韩一区二区| 一区二区免费在线观看| 狠狠入ady亚洲精品经典电影| 亚洲高清在线观看| 国产精品久久久久久久7电影| 久久久欧美精品sm网站| 欧美日韩国产综合在线| 久久综合国产精品| 欧美日韩在线播放一区二区| 久久久亚洲高清| 欧美日韩一区不卡| 美女免费视频一区| 国产精品久久毛片a| 欧美大色视频| 国产欧美一区二区精品秋霞影院| 欧美黄色免费网站| 国产午夜精品一区理论片飘花| 欧美日韩一区二区三区在线看 | 欧美日韩国产成人在线免费| 午夜精品福利电影| 欧美成人免费在线视频| 欧美一区在线视频| 欧美日韩综合网| 亚洲高清视频一区| 狠狠狠色丁香婷婷综合激情| 在线视频欧美一区| 99国产精品久久| 久久久噜久噜久久综合| 午夜精品剧场| 欧美午夜电影一区| 91久久精品一区二区别| 国精品一区二区三区| 亚洲私拍自拍| 正在播放欧美视频| 免费亚洲电影| 欧美大成色www永久网站婷| 国产欧美日韩精品a在线观看| 亚洲另类黄色| 一区二区动漫| 欧美日韩国产麻豆| 亚洲精品国产精品国产自| 亚洲日本视频| 欧美高清视频免费观看| 亚洲大片一区二区三区| 亚洲国产另类久久精品| 久久全国免费视频| 你懂的视频欧美| 亚洲国产裸拍裸体视频在线观看乱了中文 | 尤物九九久久国产精品的特点| 亚洲在线播放电影| 午夜在线视频观看日韩17c| 欧美色大人视频| 亚洲午夜精品一区二区| 亚洲视频成人| 国产免费观看久久| 久久精品二区亚洲w码| 久久先锋资源| 亚洲精品久久| 欧美日韩视频不卡| 亚洲网站在线播放| 久久国产天堂福利天堂| 国内精品视频一区| 免费观看一级特黄欧美大片| 亚洲黄色成人久久久| 亚洲午夜视频在线观看| 国产精品一区一区| 久久亚洲图片| 亚洲最快最全在线视频| 欧美与欧洲交xxxx免费观看| 狠狠v欧美v日韩v亚洲ⅴ| 欧美不卡在线| 亚洲视频在线视频| 久久久久久久性| 亚洲最新在线| 亚洲欧美另类中文字幕| 国产一区二区三区免费不卡| 久久一区二区三区av| 日韩手机在线导航| 久久久一二三| 一区二区三区免费网站| 国产亚洲aⅴaaaaaa毛片| 欧美成人嫩草网站| 亚洲尤物在线| 91久久国产综合久久91精品网站| 午夜在线a亚洲v天堂网2018| 在线播放国产一区中文字幕剧情欧美| 免费在线亚洲| 香蕉乱码成人久久天堂爱免费| 欧美插天视频在线播放| 午夜国产精品视频免费体验区| 亚洲丰满在线| 国产精品一区二区女厕厕| 久久亚洲综合色一区二区三区| 亚洲美女91| 美女精品网站| 午夜亚洲一区| 一区二区三区免费网站| 一区二区三区中文在线观看 | 欧美自拍偷拍| 在线视频欧美日韩| 亚洲大片免费看| 国产精品久在线观看| 欧美mv日韩mv国产网站app| 午夜精品久久99蜜桃的功能介绍| 亚洲国产精品一区在线观看不卡| 久久精品72免费观看| 一区二区日韩| 亚洲国产小视频在线观看| 国产一区二区无遮挡| 欧美三级黄美女| 欧美激情一区二区三区不卡| 久久久国产精品一区二区三区|