日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

_beginthreadex与CreateThread区别与联系

發(fā)布時間:2024/4/11 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 _beginthreadex与CreateThread区别与联系 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

關于這兩個函數(shù)的區(qū)別,可以參考《Windows 核心編程(第五版)》的第六章 "線程基礎",這篇文章的思想多數(shù)來源于此,我只是作了一些整理。

線程對于初學者還說可能覺得很高深,這可以理解。對于某些有經(jīng)驗的程序員來說,可能覺得又太簡單,我覺得如果認為線程很簡單的人,都是沒有理解線程,線程里面涉及的東西太多,包括內存,初始化,線程同步等。我打算以QA的形式來寫這篇文章。


Q:為什么書上說要以_beginthreadex來替代CreateThread?

A:好了,一直用API CreateThread來創(chuàng)建線程的同志們要注意了,你可能會說我一直用這個API來創(chuàng)建線程,工作剛剛的,一點問題都沒有。如果真是這樣的話,我只能說是你運氣太好了。在_beginthreadex的內部,它調用了CreateThread來創(chuàng)建線程,Windows始終用CreateThread來創(chuàng)建線程。在調用CreateThread之前,beginthreadex它做了很多初始化的工作,所以它比CreateThread創(chuàng)建的線程更加安全。


????Q:為什么要用兩個相同功能的函數(shù)來對待單線程和多線程序程序呢?

A:這里就有一定的歷史原因了,標準C語言的庫在是1970年左右發(fā)明的,而在那時候,線程的概念尚未出現(xiàn)在任何一個操作系統(tǒng)上。但是,線程畢竟是出現(xiàn)了,讓我們來看看下面這個例子,來說明以前的CRT為什么不支持多線程:

[cpp]?view plaincopy
  • BOOL?fFailure?=?(system("NOTEPAD.EXE?README.TXT")?==?-1);???
  • ????if?(fFailure)??
  • ????{???
  • ???????????switch?(errno)??
  • ???????????{??
  • ???????????case?E2BIG:??
  • ??????????????????//?Argument?list?or?environment?too?big???
  • ??????????????????break;???
  • ???????????case?ENOENT:???
  • ??????????????????//?Command?interpreter?cannot?be?found???
  • ??????????????????break;???
  • ???????????case?ENOEXEC:???
  • ??????????????????//?Command?interpreter?has?bad?format???
  • ??????????????????break;???
  • ???????????case?ENOMEM:???
  • ??????????????????//?Insufficient?memory?to?run?command???
  • ??????????????????break;??
  • ???????????}??
  • ????}??

  • 假如代碼是這種情況,當執(zhí)行到"system"這個函數(shù)之后,if之前,操作系統(tǒng)把當時CPU時鐘周期分配給另一個線程,而在另一個線程中正好使用了會設置errno(這是C語言的一個全局變量)的CRT函數(shù),于是問題就出現(xiàn)了。

    所以早期的CRT函數(shù)是沒有考慮到多線程的,在多線程中還會出問題的CRT函數(shù)還有:strtok, _wcstok, strerror, _strerror, tmpnam, tmpfile, asctime, etc. 為了保證C和C+多線程應用程序正常運行,必須創(chuàng)建一個數(shù)據(jù)結構,并使之與使用了C/C+運行庫函數(shù)的每個線程相關聯(lián),然后在調用CRT函數(shù)時,那些函數(shù)必須知道去查找主調線程的數(shù)據(jù)塊,從而避免影響到其他線程。

    那么,當系統(tǒng)創(chuàng)建線程時,它怎么知道要分配這個數(shù)據(jù)塊,又應該如何分配,它不知道,它也不知道你所調用的函數(shù)是否是線程安全,所以說,我們在創(chuàng)建新線程時,一定不要調用操作系統(tǒng)的CreateThread(Windows API)函數(shù),相反,我們始終應當調用CRT函數(shù)_beginthreadex,原型如下:

    [cpp]?view plaincopy
  • unsigned?long?_beginthreadex??
  • ?????????????????????(??
  • ?????????????????????void?*security,??
  • ?????????????????????unsigned?stack_size,???
  • ?????????????????????unsigned?(*start_address)(void?*),??
  • ?????????????????????void?*arglist,???
  • ?????????????????????unsigned?initflag,???
  • ?????????????????????unsigned?*thrdaddr??
  • ?????????????????????);??

  • _beginthreadex與CreateThread的對數(shù)列表是一樣的,只是參數(shù)名與類型不同,因為CRT函數(shù)不應該依賴于Windows的數(shù)據(jù)類型,下面有一個宏,來將CreateThread函數(shù)替換成_beginthreadex:

    [cpp]?view plaincopy
  • typedef?unsigned?(__stdcall?*?PTHREAD_START)?(void?*);???
  • ????#define?chBEGINTHREADEX(psa,?cbStack,?pfnStartAddr,?\???
  • ??????????????????????????pvParam,?fdwCreate,?pdwThreadID)?\???
  • ??????????????????????????((HANDLE)?_beginthreadex(?\???
  • ??????????????????????????(void?*)?(psa),?\??
  • ???????????????????????????(unsigned)?(cbStack),?\???
  • ??????????????????????????(PTHREAD_START)?(pfnStartAddr),\??
  • ???????????????????????????(void?*)?(pvParam),\??
  • ???????????????????????????(unsigned)?(fdwCreate),?\???
  • ??????????????????????????(unsigned?*)?(pdwThreadID)))??

  • 注意,_beginthreadex函數(shù)只存在于CRT庫的多線程版本中,如果你的程序鏈接到一個CRT單線程版本中,那么程序在鏈接時就會報錯,所以在用VS開發(fā)時,要注意這一點。

    VS里面設置如下圖所示:



    Q:為什么說_beginthreadex就要比CreateThread更好,你是怎么知道的?

    A:由于Microsoft 已經(jīng)為CRT函數(shù)提供了源碼,我們可以看到_beginthreadex到底比CreateThread多做了些什么事情,源碼在Program Files\Microsoft Visual Studio 8\VC\crt\src\Threadex.c中,可以找到_beginthreadex的實現(xiàn),這里是它的實現(xiàn):?

    _beginthreadex的源碼? [cpp]?view plaincopy
  • _MCRTIMP?uintptr_t?__cdecl?_beginthreadex?(??
  • ????????void?*security,??
  • ????????unsigned?stacksize,??
  • ????????unsigned?(__CLR_OR_STD_CALL?*?initialcode)?(void?*),??
  • ????????void?*?argument,??
  • ????????unsigned?createflag,??
  • ????????unsigned?*thrdaddr??
  • ????????)??
  • {??
  • ????????_ptiddata?ptd;????????????????????
  • ????????uintptr_t?thdl;???????????????????
  • ????????unsigned?long?err?=?0L;???????
  • ????????unsigned?dummyid;?????????????????
  • ??
  • ??????????
  • ????????_VALIDATE_RETURN(initialcode?!=?NULL,?EINVAL,?0);??
  • ??
  • ??????????
  • ????????__set_flsgetvalue();??
  • ??
  • ??????????
  • ????????if?(?(ptd?=?(_ptiddata)_calloc_crt(1,?sizeof(struct?_tiddata)))?==?NULL?)??
  • ????????????????goto?error_return;??
  • ??
  • ??????????
  • ??
  • ????????_initptd(ptd,?_getptd()->ptlocinfo);??
  • ??
  • ????????ptd->_initaddr?=?(void?*)?initialcode;??
  • ????????ptd->_initarg?=?argument;??
  • ????????ptd->_thandle?=?(uintptr_t)(-1);??
  • ??
  • #if?defined?(_M_CEE)?||?defined?(MRTDLL)??
  • ????????if(!_getdomain(&(ptd->__initDomain)))??
  • ????????{??
  • ????????????goto?error_return;??
  • ????????}??
  • #endif????
  • ??
  • ??????????
  • ????????if?(?thrdaddr?==?NULL?)??
  • ????????????????thrdaddr?=?&dummyid;??
  • ??
  • ??????????
  • ????????if?(?(thdl?=?(uintptr_t)??
  • ??????????????CreateThread(?(LPSECURITY_ATTRIBUTES)security,??
  • ????????????????????????????stacksize,??
  • ????????????????????????????_threadstartex,??
  • ????????????????????????????(LPVOID)ptd,??
  • ????????????????????????????createflag,??
  • ????????????????????????????(LPDWORD)thrdaddr))??
  • ?????????????==?(uintptr_t)0?)??
  • ????????{??
  • ????????????????err?=?GetLastError();??
  • ????????????????goto?error_return;??
  • ????????}??
  • ??
  • ??????????
  • ????????return(thdl);??
  • ??
  • ??????????
  • error_return:??
  • ??????????
  • ????????_free_crt(ptd);??
  • ??
  • ??????????
  • ????????if?(?err?!=?0L?)??
  • ????????????????_dosmaperr(err);??
  • ??
  • ????????return(?(uintptr_t)0?);??
  • }??
  • 我們要明確幾點:

    1)每個線程都有自己的專用的_tiddata內存塊,它是從C/C++的堆是分配出來的。

    2)傳給_beginthreadex的線程處理函數(shù)地址(線程的回調函數(shù)地址)是存在_tiddata內存塊中的。

    3)_beginthreadex內部的確調用了CreateThread來創(chuàng)建線程,這(CreateThread)是操作系統(tǒng)創(chuàng)建線程的唯一方式。

    4)退出線程時調用_endthreadex,它內部調用了API ExitThread,它會釋放創(chuàng)建線程在堆上分配的內存_tiddata。


    Q:我要怎么終止線程?

    A:與_beginthreadex相對應的退出線程的函數(shù)是_endthreadex,CreateThread 對應 ExitThread,一般情況下我們不要調用這兩個函數(shù)來終止線程,最好是讓線程走完它的線程處理函數(shù),讓它自生自滅。如果要調用的話,最好調用_endthreadex,但一般不推薦。

    OK, 目前為止你應該對誰更好些的問題有了深入的了解,但是為什么調用CreateThread的程序仍然可以經(jīng)年累月的正常運行呢?當線程調用一個需要 tiddata結構的CRT函數(shù)時(大多數(shù)CRT函數(shù)是線程安全的,并不需要該結構),首先CRT函數(shù)試圖獲取線程的數(shù)據(jù)塊的地址(通過調用 TlsGetValue),然后,如果返回NULL,說明調用線程沒有相關聯(lián)的tiddata塊,那么CRT函數(shù)馬上為調用線程分配并初始化一個 tiddata塊,并將該內存塊關聯(lián)到線程(通過TlsSetValue),這樣,該CRT函數(shù)以及其他CRT函數(shù)都可以使用該線程的tiddata塊了 (此即所謂"前人栽樹后人乘涼"了,_)。

    當然,如果說你的線程運行的時候一直沒有問題是幾乎不可能的。事實上,的確有一些問題需要說說。如 果線程使用了CRT的signal函數(shù),整個進程都會被中止,因為結構化異常處理體尚未準備好。同樣,如果不調用_endthreadex來中止線程就會 造成內存泄漏,如果使用_beginthreadex,當然會容易想到_endthreadex,但如果你習慣了使用CreateThread,是否還會 想起_endthreadex,我表示極大的懷疑,而且CreateThread/_endthreadex的組合怎么看怎么讓人別扭。
    不要忘記 開始的問題,接下來讓我們再來看看效率問題。CRT庫的多線程版本在某些函數(shù)里面放置了同步原語,比如malloc,為了保證堆不會被同時調用的 malloc函數(shù)破壞,這不可避免地會對效率造成影響,C/C++的哲學我們不應忘記,"決不為自己沒有用到的付出代價",自然,我們無權要求單線程程序 為多線程程序付出它們不該付出的代價,所以,開頭的問題也有了答案。
    上面所說的都是靜態(tài)鏈接的CRT庫,而CRT庫的動態(tài)鏈接版本則被編寫得更加 通用,以便能夠被任何運行的程序和DLL共享。正是基于這個原因,這個版本的庫只存在多線程版本。因為CRT庫是以DLL形式提供的,程序和DLL不需要 包含CRT庫的任何代碼,自然尺寸也就更小。同時,如果Microsoft修正了CRT庫DLL中的Bug,程序也就自然受益了。


    總結

    首先,如果你調用_beginthreadex,你會獲得線程的句柄,句柄當然需要關閉,但_endthreadex并沒有這么做。通 常是調用_beginthreadex的線程(很可能是主線程)來調用CloseHandle關閉不再需要的新線程的句柄。其次,如果你使用CRT函數(shù), 你只需要使用_beginthreadex即可。如果不使用,那么你可以只使用CreateThread。同樣,如果只有一個線程(主線程)使用 CRT,你也可以使用CreateThread;如果新創(chuàng)建的線程不使用CRT,那么你也不需要_beginthreadex和多線程CRT。

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的_beginthreadex与CreateThread区别与联系的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 黄色一及片 | 麻豆传媒一区 | 欧美激情亚洲色图 | 四虎永久网址 | 激情文学亚洲色图 | 超碰在线国产 | 欧美热热 | 久久99久久99精品 | 欧美老女人性生活视频 | 国产在线拍揄自揄拍 | 毛片a区 | 国产在线观看免费网站 | 噜噜av| 9999在线视频 | 夜色网| 亚洲国产精品视频一区 | 97一级片 | 奶波霸巨乳一二三区乳 | 国产精品jizz在线观看无码 | www日本黄色 | 日韩人妻无码精品久久免费 | 黄色大片视频网站 | 一级久久久久 | 一区二区三区视频在线 | 欧美被狂躁喷白浆精品 | 国产不卡一区二区视频 | 亚洲国产成人精品91久久久 | 男人天堂社区 | 成人美女在线观看 | 欧美日韩另类视频 | 伊人激情| 91久久精品美女高潮 | 91精品国产99久久久久久红楼 | av图区 | 青草视频在线观看免费 | 国模吧无码一区二区三区 | 自拍偷拍中文字幕 | 日韩高清在线观看 | 亚洲中文字幕无码av永久 | 污污视频网站免费观看 | 国产伦理吴梦梦伦理 | 色噜噜狠狠狠综合曰曰曰 | 一本到在线观看 | 这里只有精品在线播放 | 99色精品| 成人综合婷婷国产精品久久 | 亚洲天堂一区二区三区四区 | 亚洲视频二 | 91在线免费观看网站 | 免费人成在线观看 | 精品无码久久久久久久久久 | 国产成人黄色 | 少妇闺蜜换浪荡h肉辣文 | 亚洲色图网站 | 国产 福利 在线 | 久久久精品蜜桃 | 欧美成年人视频在线观看 | 日韩一级片在线观看 | 免费在线观看黄色av | 青青草原免费观看 | 久久久久www| 欧美brazzers | 午夜在线一区 | 日韩短视频 | 牲欲强的熟妇农村老妇女视频 | 特大黑人巨交性xxxx | 中国毛片网 | 人体裸体bbb欣赏 | 神马午夜激情 | 久久色在线 | 国内精品偷拍 | 美女扒开下面让男人捅 | 师生出轨h灌满了1v1 | 奇米影视狠狠 | 日日夜夜撸撸 | 播放灌醉水嫩大学生国内精品 | 欧美混交群体交 | 国产欧美久久一区二区三区 | av我不卡 | 欧美性大交 | 色悠悠国产精品 | 麻豆精品久久久久久久99蜜桃 | 欧美性三级 | 久久久精品人妻一区二区三区 | aaaa一级片| 国产伦精品一区二区三区免.费 | 久久久影院 | 国产成人精品一区二区三区在线观看 | 久久一区欧美 | 一个人免费在线观看视频 | 免费三级网| av片免费在线| 农村妇女av | 香蕉国产精品 | 国产一区二区播放 | 久久成人激情 | 91精品国产综合久久久密臀九色 | 色呦呦在线播放 | a一级免费视频 |