Windows threading: _beginthread vs _beginthreadex vs CreateThread C ++

133

Apa cara yang lebih baik untuk memulai utas _beginthread,, _beginthreadxatau CreateThread?

Saya mencoba menentukan apa kelebihan / kekurangan _beginthread, _beginthreadexdan CreateThread. Semua fungsi ini mengembalikan gagang utas ke utas yang baru dibuat, saya sudah tahu bahwa CreateThread memberikan sedikit informasi tambahan ketika terjadi kesalahan (bisa diperiksa dengan menelepon GetLastError) ... tapi apa saja beberapa hal yang harus saya pertimbangkan ketika saya ' saya menggunakan fungsi-fungsi ini?

Saya bekerja dengan aplikasi windows, jadi kompatibilitas lintas-platform sudah keluar dari pertanyaan.

Saya telah membaca dokumentasi msdn dan saya tidak bisa mengerti, misalnya, mengapa ada orang yang memutuskan untuk menggunakan _beginthread alih-alih CreateThread atau sebaliknya.

Bersulang!

Pembaruan: OK, terima kasih untuk semua informasinya, saya juga sudah membaca di beberapa tempat yang tidak bisa saya hubungi WaitForSingleObject()jika saya gunakan _beginthread(), tetapi jika saya menelepon _endthread()di utas, apakah itu tidak berfungsi? Apa masalahnya di sana?

Kiril
sumber
2
Berikut adalah analisis tentang apa yang dilakukan _beginthreadex () untuk programmer C / C ++ yang saya temukan dari tautan di situs web Eli Bendersky. Ini dari T&J apakah akan menggunakan CreateThread () atau tidak. microsoft.com/msj/0799/win32/win320799.aspx
Richard Chambers

Jawaban:

96

CreateThread() adalah panggilan API Win32 mentah untuk membuat utas kontrol lain di tingkat kernel.

_beginthread()& _beginthreadex()adalah panggilan pustaka runtime C yang memanggil di CreateThread()belakang layar. Setelah CreateThread()kembali, _beginthread/ex()kelola pembukuan tambahan untuk membuat pustaka runtime C dapat digunakan & konsisten di utas baru.

Dalam C ++ Anda hampir pasti harus menggunakan _beginthreadex()kecuali Anda tidak akan menautkan ke perpustakaan runtime C sama sekali (alias MSVCRT * .dll / .lib).

Drew Hall
sumber
39
Ini tidak lagi benar seperti dulu. CRT akan berfungsi dengan benar di utas yang dibuat oleh CreateThread () dengan pengecualian fungsi he signal (). Akan ada kebocoran memori kecil (~ 80 byte) untuk setiap utas yang dibuat dengan CreateThread () yang menggunakan CRT, tetapi akan berfungsi dengan benar. Lihat untuk info lebih lanjut: support.microsoft.com/default.aspx/kb/104641
John Dibling
1
@ John: Sebenarnya bug itu hanya berlaku hingga MSVC ++ 6.0
bobobobo
5
@obobobo: Pertanyaan bagus. Saya hanya bisa berspekulasi bahwa MS awalnya dimaksudkan sebagai _beginrutinitas panggilan internal dan CreateThreadseharusnya menjadi fungsi API semua orang akan memanggil. Penjelasan potensial lainnya adalah bahwa MS memiliki sejarah panjang & mulia mengabaikan standar & membuat keputusan yang sangat buruk tentang penamaan sesuatu.
John Dibling
15
The _beginfungsi mulai dengan garis bawah karena Microsoft mulai mengikuti standar lebih dekat. Dalam runtime C, nama-nama yang berada dengan garis bawah dicadangkan untuk implementasi (dan implementasinya dapat mendokumentasikannya untuk penggunaan pengguna akhir, seperti ini). beginthreadex()adalah nama yang diizinkan untuk digunakan oleh pengguna. Jika runtime C menggunakannya, maka itu mungkin bertentangan dengan simbol pengguna akhir yang berhak sah untuk bisa digunakan pengguna. Perhatikan bahwa API Win32 bukan bagian dari runtime C, dan mereka menggunakan namespace pengguna.
Michael Burr
2
@Lothar: Ada yang perbedaan antara Win32 API panggilan CreateThreaddan panggilan CRT _beginthread/ex, dan saat memanggil CRT pada benang, itu harus selalu dibuat dengan _beginthread/ex. Mungkin tidak ada lagi kebocoran memori, jika Anda tidak. Tapi Anda pasti tidak akan mendapatkan lingkungan titik apung diinisialisasi dengan benar saat menelepon CreateThread, misalnya. Masih ada lagi : "Jika utas yang dibuat menggunakan CreateThread memanggil CRT, CRT dapat menghentikan proses dalam kondisi memori rendah."
IInspectable
37

Ada beberapa perbedaan antara _beginthread()dan _beginthreadex(). _beginthreadex()dibuat untuk bertindak lebih seperti CreateThread()(di kedua parameter dan bagaimana perilakunya).

Seperti yang dikatakan Drew Hall , jika Anda menggunakan runtime C / C ++, Anda harus menggunakan _beginthread()/ _beginthreadex()bukannya CreateThread()agar runtime memiliki kesempatan untuk melakukan inisialisasi utas sendiri (menyiapkan penyimpanan lokal utas, dll.).

Dalam praktiknya, ini berarti bahwa CreateThread()seharusnya tidak banyak digunakan secara langsung oleh kode Anda.

Dokumen MSDN untuk _beginthread()/ _beginthreadex()memiliki sedikit detail tentang perbedaan - salah satu yang lebih penting adalah bahwa sejak ulir menangani utas yang dibuat oleh_beginthread() akan ditutup secara otomatis oleh CRT ketika utas keluar, "jika utas yang dihasilkan oleh _beginthread keluar cepat, gagang kembali ke pemanggil _beginthread mungkin tidak valid atau, lebih buruk, arahkan ke utas lainnya ".

Berikut komentar _beginthreadex()dari sumber CRT:

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

Pembaruan Jan 2013:

CRT untuk VS 2012 memiliki sedikit inisialisasi tambahan yang dilakukan di _beginthreadex(): jika prosesnya adalah "aplikasi terpaket" (jika sesuatu yang bermanfaat dikembalikan GetCurrentPackageId()) runtime akan menginisialisasi MTA pada utas yang baru dibuat.

Michael Burr
sumber
3
Ada saat-saat yang tepat ketika CreateThread () dibenarkan, tetapi jujur ​​Anda benar-benar harus keluar dari cara Anda untuk melakukannya. Kita berbicara tentang kekurangan apa pun yang portabel dan menulis DLL atau Aplikasi WIN32 secara eksklusif. Termasuk tidak ada panggilan C-runtime. Bahkan penggunaan STL terbatas karena Anda harus menyediakan pengalokasi khusus untuk menggunakan fungsi manajemen memori WIN32. Pengaturan untuk melakukan ini dengan Developer Studio adalah pekerjaan itu sendiri, tetapi untuk lib WIN32 satu-satunya dengan jejak sekecil mungkin, itu bisa dilakukan. Tapi ya, itu tidak berdarah bagi hampir semua orang kecuali beberapa orang.
WhozCraig
1
@WhozCraig: Ada batasan yang lebih parah saat menghilangkan CRT. Yang paling menonjol adalah: Tidak ada dukungan integer 64-bit, tidak ada dukungan floating point, dan - paling drastis - tidak terkecuali penanganan. Ini benar-benar berarti penanganan tanpa pengecualian - sama sekali . Bahkan pengecualian SEH. Ini sangat sulit untuk ditebus, dan peluang untuk memanggil CreateThreadmenjadi Hal yang Benar semakin tipis.
IInspectable
@MichaelBurr: Anda mungkin ingin memperbarui jawaban Anda untuk VC ++ 2015 .
user541686
@Mehrdad: Perubahan mana yang menurut Anda pantas untuk disebutkan?
IInspectable
Saya telah menemukan bahwa DisableThreadLibraryCalls tidak berpengaruh pada utas yang dibuat dengan CreateThread, tetapi tidak menonaktifkan utas yang dibuat dengan _beginthread atau _beginthreadex.
SPlatten
23

Secara umum, hal yang benar untuk dilakukan adalah memanggil _beginthread()/_endthread()(atau ex()variannya). Namun, jika Anda menggunakan CRT sebagai .dll, status CRT akan diinisialisasi dan dihancurkan dengan benar karena CRT DllMainakan dipanggil bersama DLL_THREAD_ATTACHdan DLL_THREAD_DETACHketika memanggil CreateThread()dan ExitThread()atau kembali, masing-masing.

The DllMainkode untuk CRT dapat ditemukan dalam direktori instalasi untuk VS bawah VC \ crt \ src \ crtlib.c.

MSN
sumber
Titik awal yang bagus. Dengan sedikit debug, orang dapat menunjukkan __CRTDLL_INIT dipanggil bahkan untuk CRT yang terhubung secara statis. Callstack init dipanggil dari _LdrpCallInitRoutine @ 16 (), saya tidak yakin persis dengan mekanisme apa. Ini berarti dengan CRT baru-baru ini semua inisialisasi / deinitialisasi dilakukan dengan benar dengan pengecualian penanganan sinyal, yang masih dilakukan dalam fungsi helper _threadstartex disebut dari beginthread, tetapi tidak dari CreateThread. Mungkin Anda bisa menambahkan ini ke dalam jawaban dan saya akan memberikan hadiahnya?
Suma
Karunia diberikan, karena ini tampaknya paling membantu. Namun, jawabannya mungkin layak diperbarui. Jika Anda tidak dapat melakukannya, saya dapat mengunjungi kembali dalam beberapa hari.
Suma
1
@MSN: Perlu diketahui, bahwa CreateThread masih buruk di DLL, jika Anda menautkan kembali CRT statis dan telah memanggil DisableThreadLibraryCalls yang menonaktifkan panggilan untuk DLL_THREAD_DETACH. Maka Anda akan mendapatkan kebocoran memori. Ini didokumentasikan di sini di artikel KB saya: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach
17

Ini adalah kode pada inti _beginthreadex(lihat crt\src\threadex.c):

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

Sisa _beginthreadexinisialisasi struktur data per-utas untuk CRT.

Keuntungan menggunakan _beginthread*adalah bahwa panggilan CRT Anda dari utas akan bekerja dengan benar.

Konstantin
sumber
12

Anda harus menggunakan _beginthreadatau _beginthreadexmengizinkan pustaka runtime C untuk melakukan inisialisasi dari utas itu sendiri. Hanya programmer C / C ++ yang perlu mengetahui hal ini karena mereka seharusnya sekarang memiliki aturan untuk menggunakan lingkungan pengembangan mereka sendiri.

Jika Anda menggunakan, _beginthreadAnda tidak perlu menelepon CloseHandlekarena RTL akan melakukannya untuk Anda. Inilah sebabnya mengapa Anda tidak bisa menunggu jika Anda sudah menggunakannya _beginthread. Juga _beginthreadmenyebabkan kebingungan jika fungsi utas keluar segera (dengan cepat) saat utas peluncur dibiarkan memegang pegangan utas yang tidak valid pada utas yang baru saja diluncurkan.

_beginthreadexpegangan dapat digunakan untuk menunggu tetapi juga membutuhkan panggilan eksplisit untuk CloseHandle. Ini adalah bagian dari apa yang membuat mereka aman untuk digunakan dengan menunggu. Ada masalah lain untuk membuatnya benar-benar aman adalah untuk selalu memulai utas ditangguhkan. Periksa keberhasilan, pegangan rekaman, dll. Utas resume. Ini diperlukan untuk mencegah utas dari pengakhiran sebelum utas peluncuran dapat merekam pegangannya.

Praktik terbaik adalah menggunakan _beginthreadex, mulai ditangguhkan kemudian lanjutkan setelah pegangan rekaman, tunggu pegangan itu OK, CloseHandleharus dipanggil.

jarcher7
sumber
8

CreateThread()dulu ada kebocoran memori saat Anda menggunakan fungsi CRT dalam kode Anda. _beginthreadex()memiliki parameter yang sama CreateThread()dan lebih fleksibel daripada _beginthread(). Jadi saya sarankan Anda gunakan _beginthreadex().

Jaywalker
sumber
2
Artikel 1999, mungkin sejak itu diperbaiki
bobobobo
1
Artikel ini dari tahun 2005 masih mengkonfirmasi bahwa ada masalah.
Jaywalker
2
Ya, itu hanya berlaku untuk MSVC ++ 6.0 Paket Layanan 5 dan sebelumnya. (lihat "Berlaku untuk" dropdown yang dapat diperluas). Ini bukan masalah hari ini jika Anda menggunakan VC7 atau lebih tinggi.
bobobobo
1
Ini masih menjadi masalah, jika Anda menautkan dengan CRT statis! Juga masih menjadi masalah jika Anda memanggil DisableThreadLibraryCalls di DLL yang terhubung secara statis; lihat artikel KB saya: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach
2
Anda salah mengartikan informasi: CreateThreadtidak tidak pernah bocor memori. Ini bukan CRT yang melakukannya, ketika dipanggil dari utas yang belum diinisialisasi dengan benar.
IInspectable
6

Mengenai pertanyaan Anda yang diperbarui: "Saya juga membaca di beberapa tempat yang tidak bisa saya hubungi WaitForSingleObject()jika saya gunakan _beginthread(), tetapi jika saya menelepon _endthread()di utas, bukankah itu berhasil?"

Secara umum, Anda bisa meneruskan pegangan utas ke WaitForSingleObject()(atau API lain yang menunggu gagang objek) untuk memblokir sampai utas selesai. Tetapi pegangan thread yang dibuat oleh _beginthread()ditutup ketika _endthread()dipanggil (yang dapat dilakukan secara eksplisit atau dilakukan secara implisit oleh waktu berjalan ketika prosedur thread kembali).

Masalahnya disebutkan dalam dokumentasi untuk WaitForSingleObject():

Jika pegangan ini ditutup saat menunggu masih menunggu, perilaku fungsi tidak terdefinisi.

Michael Burr
sumber
5

Melihat fungsi tanda tangan, CreateThreadhampir identik dengan _beginthreadex.

_beginthread,_beginthreadx vsCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

Pernyataan di sini mengatakan _beginthreadbisa menggunakan salah satu __cdeclatau__clrcall memanggil konvensi sebagai titik awal, dan _beginthreadexdapat menggunakan salah satu __stdcallatau __clrcalluntuk titik awal.

Saya pikir setiap komentar yang dibuat orang mengenai kebocoran memori sudah CreateThreadberusia lebih dari satu dekade dan mungkin harus diabaikan.

Menariknya, kedua _beginthread*fungsi ini sebenarnya memanggil di CreateThreadbawah kap, di C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\srcpada mesin saya.

// From ~line 180 of beginthreadex.c
/*
 * Create the new thread using the parameters supplied by the caller.
 */
if ( (thdl = (uintptr_t)
      CreateThread( (LPSECURITY_ATTRIBUTES)security,
                    stacksize,
                    _threadstartex,
                    (LPVOID)ptd,
                    createflag,
                    (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
{
        err = GetLastError();
        goto error_return;
}
bobobobo
sumber
2
Komentar, mengapa Anda tidak harus membuat CreateThread dan mencampur panggilan CRT pada utas itu (jelas tidak berumur satu dekade, dan pastinya tidak boleh diabaikan) : "Jika sebuah utas yang dibuat menggunakan CreateThread memanggil CRT, CRT dapat menghentikan proses dalam kondisi memori rendah. "
IInspectable
3

beginthreadexmemberi Anda utas HANDLEuntuk digunakan dalam WaitForSingleObjectdan teman-teman. beginthreadtidak. Jangan lupa CloseHandle()kapan Anda selesai. Jawaban sebenarnya adalah menggunakan boost::threadatau segera kelas utas C ++ 09.

MD XF
sumber
Deskripsi msdn mengatakan bahwa "Jika berhasil, masing-masing fungsi ini mengembalikan pegangan ke utas yang baru dibuat;" merujuk ke _beginthread () dan _beginthreadex () ...
Kiril
@ Kiril: tapi kemudian dokumentasi melanjutkan dengan mengatakan bahwa _beginthread menutup gagang untuk Anda, artinya Anda tidak dapat menggunakannya jika utas keluar dengan cepat ...
Roger Lipscombe
2

Dibandingkan dengan _beginthread, _beginthreadexAnda dapat:

  1. Tentukan atribut keamanan.
  2. Mulai utas dalam status ditangguhkan.
  3. Anda bisa mendapatkan id utas yang dapat digunakan OpenThread .
  4. Pegangan utas yang dikembalikan dijamin valid jika panggilan berhasil. Untuk itu Anda harus menutup gagangnyaCloseHandle .
  5. Pegangan utas yang dikembalikan dapat digunakan dengan API sinkronisasi.

Sangat _beginthreadexmirip CreateThread, tetapi yang pertama adalah implementasi CRT dan yang terakhir panggilan Windows API. Dokumentasi untuk CreateThread berisi rekomendasi berikut:

Utas dalam executable yang memanggil C run-time library (CRT) harus menggunakan _beginthreadexdan _endthreadexfungsi untuk manajemen utas daripada CreateThreaddan ExitThread; ini membutuhkan penggunaan versi CRT multi-utas. Jika utas yang dibuat menggunakan CreateThreadpanggilan CRT, CRT dapat menghentikan proses dalam kondisi memori rendah.

Vishal
sumber
Menurut spesifikasi API, poin-poin 3-5 tidak unik untuk _beginthreadex. Anda dapat uintptr_tmengembalikan dari kedua fungsi tersebut ke HANDLE.
Andon M. Coleman
Ya, Anda benar dalam teori. Dalam praktiknya, perbedaannya adalah bahwa _beginthreadmenutup pegangan saat keluar. Jadi, Anda tidak dapat menggunakan pegangan dengan andal API sinkronisasi atau untuk mendapatkan id utas sampai dan kecuali Anda menggunakan cara lain untuk menyinkronkan dan menduplikasi pegangan. Tetapi kemudian ada _beginthreadexmelakukannya untuk Anda.
Vishal
2

CreateThread()dulu adalah tidak-tidak karena CRT akan salah menginisialisasi / membersihkan. Tapi ini sekarang sejarah: Seseorang sekarang dapat (menggunakan VS2010 dan mungkin beberapa versi kembali) memanggil CreateThread()tanpa melanggar CRT.

Ini konfirmasi resmi MS . Ini menyatakan satu pengecualian:

Sebenarnya, satu-satunya fungsi yang tidak boleh digunakan dalam utas yang dibuat CreateThread()adalah signal()fungsi.

Namun, dari sudut pandang konsistensi, saya pribadi lebih suka tetap menggunakan _beginthreadex().

Serge Wautier
sumber
Walaupun saya menganggap ini benar, dapatkah Anda memberikan beberapa bukti otoritatif - baik dengan menautkan ke Dokumentasi MS, atau dengan menganalisis sumber CRT _beginthreadex / _endthreadex?
Suma
@ Souma, saya kira saya menambahkan tautan MS itu ketika Anda mengetik komentar Anda ;-)
Serge Wautier
Dokumen yang Anda tautkan tampaknya tidak mengonfirmasi: "Namun, tergantung pada apa yang disebut fungsi CRT, mungkin ada sedikit kebocoran memori ketika utas diakhiri.". Ini berarti ia tidak lagi besar dan umum tidak-tidak, tetapi masih tidak-tidak jika Anda sering membuat utas dan menggunakan fungsi-fungsi itu di dalamnya. Namun, dokumen tersebut berasal dari tahun 2005 dan karena itu tidak dapat membahas keadaan terkini dari masalah tersebut.
Suma
1
Hmm ... meskipun mungkin tergantung pada use case, fungsi meninggalkan kebocoran memori, tidak peduli ukurannya, saya akan mempertimbangkan tidak-tidak ... - khususnya jika ada alternatif yang tidak bocor!
alk
"Seseorang sekarang dapat memanggil CreateThread () tanpa melanggar CRT." - Sayangnya, ini tidak benar, dan tidak pernah terjadi. Dari CreateThread : "Sebuah thread dalam executable yang memanggil C run-time library (CRT) harus menggunakan fungsi _beginthreadex dan _endthreadex untuk manajemen thread [...] Jika sebuah thread yang dibuat menggunakan CreateThread memanggil CRT, CRT dapat mengakhiri proses dalam kondisi memori rendah. "
IInspectable
2

CreateThread()adalah panggilan Windows API yang netral bahasa. Itu hanya menciptakan objek OS - utas dan mengembalikan HANDLE ke utas ini. Semua aplikasi windows menggunakan panggilan ini untuk membuat utas. Semua bahasa menghindari panggilan API langsung karena alasan yang jelas: 1. Anda tidak ingin kode Anda spesifik untuk OS 2. Anda perlu melakukan beberapa pemeliharaan rumah sebelum memanggil seperti API: mengonversi parameter dan hasil, mengalokasikan penyimpanan sementara dll.

_beginthreadex()adalah C wrapper di sekitar CreateThread()yang menyumbang C spesifik. Ini memungkinkan C f-n berulir tunggal asli bekerja di lingkungan multithreaded dengan mengalokasikan penyimpanan spesifik thread.

Jika Anda tidak menggunakan CRT, Anda tidak dapat menghindari panggilan langsung ke CreateThread(). Jika Anda menggunakan CRT, Anda harus menggunakan _beginthreadex()atau string CRT f-ns mungkin tidak berfungsi dengan benar sebelum VC2005.

SKV
sumber
1

CreateThread()adalah panggilan sistem langsung. Diimplementasikan di Kernel32.dllmana, kemungkinan besar, aplikasi Anda sudah akan ditautkan karena alasan lain. Itu selalu tersedia di sistem Windows modern.

_beginthread()dan _beginthreadex()fungsi pembungkus dalam Microsoft C Runtime ( msvcrt.dll). Perbedaan antara kedua panggilan dinyatakan dalam dokumentasi. Dengan demikian tersedia ketika Microsoft C Runtime tersedia, atau jika aplikasi Anda terhubung secara statis dengannya. Anda mungkin juga akan menautkan ke perpustakaan itu, kecuali jika Anda mengode dalam API Windows murni (seperti yang sering saya lakukan).

Pertanyaan Anda koheren dan sebenarnya berulang. Seperti banyak API, ada fungsi ganda dan ambigu dalam API Windows yang harus kita tangani. Terburuk dari semua, dokumentasi tidak menjelaskan masalah ini. Saya kira _beginthread()keluarga fungsi diciptakan untuk integrasi yang lebih baik dengan fungsionalitas standar C lainnya, seperti manipulasi errno._beginthread()dengan demikian terintegrasi lebih baik dengan runtime C.

Meskipun begitu, kecuali jika Anda memiliki alasan yang baik untuk menggunakan _beginthread()atau _beginthreadex(), Anda harus menggunakan CreateThread(), sebagian besar karena Anda mungkin mendapatkan satu ketergantungan perpustakaan yang kurang dalam eksekusi akhir Anda (dan untuk MS CRT ini sedikit berpengaruh). Anda juga tidak memiliki kode pembungkus di sekitar panggilan, meskipun efek ini dapat diabaikan. Dengan kata lain, saya percaya bahwa alasan utama untuk bertahan CreateThread()adalah karena tidak ada alasan yang baik _beginthreadex()untuk memulainya. Fungsionalitasnya persis, atau hampir, sama.

Salah satu alasan yang baik untuk menggunakan _beginthread() akan (karena tampaknya salah) bahwa objek C ++ akan benar-benar ditarik / dihancurkan jika _endthread()dipanggil.

alecov
sumber
Tidak ada panggilan fungsi ambigu sama sekali . CreateThreadadalah panggilan Windows API untuk membuat utas. Jika Anda menggunakan CRT (karena Anda memprogram dalam C atau C ++), Anda harus membuat utas menggunakan _beginthread[ex]panggilan CRT (yang memanggil CreateThreadselain melakukan inisialisasi CRT yang diperlukan). Perbedaan paling penting antara _beginthreaddan varian sebelumnya: Yang pertama mempertahankan kepemilikan dari pegangan utas asli, sedangkan yang kedua meneruskan kepemilikan kepada penelepon.
IInspectable
Nitpick: msvcrt.dlladalah tidak C runtime DLL! Lihat blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273
Govind Parmar
0

Jawaban lain gagal untuk membahas implikasi memanggil fungsi run-time C yang membungkus fungsi Win32 API. Ini penting ketika mempertimbangkan perilaku mengunci loader DLL.

Terlepas dari _beginthread{ex}apakah manajemen benang Runtime C / benang memori serat khusus atau yang dijawab oleh jawaban lain, ini diterapkan dalam (dengan asumsi penghubungan dinamis dengan waktu berjalan C) DLL yang memproses mungkin belum dimuat.

Hal ini tidak aman untuk memanggil _beginthread*dari DllMain. Saya telah menguji ini dengan menulis DLL yang dimuat menggunakan fitur "AppInit_DLLs" Windows. Memanggil _beginthreadex (...)alih-alih CreateThread (...)menyebabkan BANYAK bagian penting Windows berhenti berfungsi saat bootup karena DllMaindeadlock kunci-entri menunggu kunci loader dirilis untuk melakukan tugas inisialisasi tertentu.

Kebetulan, ini juga mengapa kernel32.dll memiliki banyak fungsi string yang tumpang tindih dengan C run-time juga - gunakan yang dari DllMainuntuk menghindari situasi yang sama.

Andon M. Coleman
sumber
0

Jika Anda membaca buku Debugging Windows Application Dari Jeffrey Richter di dalamnya, ia menjelaskan bahwa hampir dalam semua hal Anda harus menelepon _beginthreadexalih-alih menelepon CreateThread. _beginthreadhanyalah pembungkus sederhana di sekitar _beginthreadex.

_beginthreadexmenginisialisasi internal CRT (C RunTime) tertentu yang CreateThreadtidak akan dilakukan API.

Konsekuensi jika Anda menggunakan CreateThreadAPI alih-alih menggunakan _begingthreadexpanggilan ke fungsi CRT dapat menyebabkan masalah yang tidak terduga.

Lihat Microsoft Journal From Richter lama ini.

Ehsan Samani
sumber
-2

Tidak ada perbedaan lagi antara keduanya.

Semua komentar tentang kebocoran memori dll didasarkan pada <VS2005 versi yang sangat lama. Saya telah melakukan beberapa pengujian stres bertahun-tahun yang lalu dan dapat menghilangkan prasangka mitos ini. Bahkan Microsoft mencampur gaya dalam contoh mereka, hampir tidak pernah menggunakan _beginthread.

Lothar
sumber
CreateThread : "Jika sebuah thread yang dibuat menggunakan CreateThread memanggil CRT, CRT dapat menghentikan proses dalam kondisi memori rendah."
IInspectable
Berdasarkan subsensi "memerlukan penggunaan versi CRT multithreaded" saya berasumsi ini adalah dokumentasi sampah karena tidak ada versi crt multithreaded lagi dan selama bertahun-tahun sekarang.
Lothar
"tidak ada versi crt multithreaded lagi" - MSDN mengklaim bahwa "[t] dia single-threaded CRT tidak lagi tersedia." Anda berdua tidak bisa benar. Saya akan pergi dengan MSDN di sini juga.
IInspectable
Itu salah ketik, tentu saja saya maksudkan bahwa utas tunggal sudah hilang dan multithreaded telah menjadi standar dan yang hilang adalah perbedaan antara menggunakan atau tidak menggunakan utas.
Lothar
Ini benar-benar semakin aneh. Anda sekarang menggunakan pernyataan, yang tidak diragukan lagi benar ( "mengharuskan penggunaan versi CRT yang multithreaded" ) untuk mengklaim bahwa pernyataan ini serta sisa dokumentasi tersebut kemungkinan besar salah? Itu tidak terdengar benar.
IInspectable