Apa cara yang lebih baik untuk memulai utas _beginthread
,, _beginthreadx
atau CreateThread
?
Saya mencoba menentukan apa kelebihan / kekurangan _beginthread
, _beginthreadex
dan 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?
sumber
Jawaban:
CreateThread()
adalah panggilan API Win32 mentah untuk membuat utas kontrol lain di tingkat kernel._beginthread()
&_beginthreadex()
adalah panggilan pustaka runtime C yang memanggil diCreateThread()
belakang layar. SetelahCreateThread()
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).sumber
_begin
rutinitas panggilan internal danCreateThread
seharusnya 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._begin
fungsi 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.CreateThread
dan 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 meneleponCreateThread
, misalnya. Masih ada lagi : "Jika utas yang dibuat menggunakan CreateThread memanggil CRT, CRT dapat menghentikan proses dalam kondisi memori rendah."Ada beberapa perbedaan antara
_beginthread()
dan_beginthreadex()
._beginthreadex()
dibuat untuk bertindak lebih sepertiCreateThread()
(di kedua parameter dan bagaimana perilakunya).Seperti yang dikatakan Drew Hall , jika Anda menggunakan runtime C / C ++, Anda harus menggunakan
_beginthread()
/_beginthreadex()
bukannyaCreateThread()
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:Pembaruan Jan 2013:
CRT untuk VS 2012 memiliki sedikit inisialisasi tambahan yang dilakukan di
_beginthreadex()
: jika prosesnya adalah "aplikasi terpaket" (jika sesuatu yang bermanfaat dikembalikanGetCurrentPackageId()
) runtime akan menginisialisasi MTA pada utas yang baru dibuat.sumber
CreateThread
menjadi Hal yang Benar semakin tipis.Secara umum, hal yang benar untuk dilakukan adalah memanggil
_beginthread()/_endthread()
(atauex()
variannya). Namun, jika Anda menggunakan CRT sebagai .dll, status CRT akan diinisialisasi dan dihancurkan dengan benar karena CRTDllMain
akan dipanggil bersamaDLL_THREAD_ATTACH
danDLL_THREAD_DETACH
ketika memanggilCreateThread()
danExitThread()
atau kembali, masing-masing.The
DllMain
kode untuk CRT dapat ditemukan dalam direktori instalasi untuk VS bawah VC \ crt \ src \ crtlib.c.sumber
Ini adalah kode pada inti
_beginthreadex
(lihatcrt\src\threadex.c
):Sisa
_beginthreadex
inisialisasi struktur data per-utas untuk CRT.Keuntungan menggunakan
_beginthread*
adalah bahwa panggilan CRT Anda dari utas akan bekerja dengan benar.sumber
Anda harus menggunakan
_beginthread
atau_beginthreadex
mengizinkan 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,
_beginthread
Anda tidak perlu meneleponCloseHandle
karena RTL akan melakukannya untuk Anda. Inilah sebabnya mengapa Anda tidak bisa menunggu jika Anda sudah menggunakannya_beginthread
. Juga_beginthread
menyebabkan kebingungan jika fungsi utas keluar segera (dengan cepat) saat utas peluncur dibiarkan memegang pegangan utas yang tidak valid pada utas yang baru saja diluncurkan._beginthreadex
pegangan dapat digunakan untuk menunggu tetapi juga membutuhkan panggilan eksplisit untukCloseHandle
. 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,CloseHandle
harus dipanggil.sumber
CreateThread()
dulu ada kebocoran memori saat Anda menggunakan fungsi CRT dalam kode Anda._beginthreadex()
memiliki parameter yang samaCreateThread()
dan lebih fleksibel daripada_beginthread()
. Jadi saya sarankan Anda gunakan_beginthreadex()
.sumber
CreateThread
tidak tidak pernah bocor memori. Ini bukan CRT yang melakukannya, ketika dipanggil dari utas yang belum diinisialisasi dengan benar.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()
:sumber
Melihat fungsi tanda tangan,
CreateThread
hampir identik dengan_beginthreadex
._beginthread
,_beginthreadx
vsCreateThread
Pernyataan di sini mengatakan
_beginthread
bisa menggunakan salah satu__cdecl
atau__clrcall
memanggil konvensi sebagai titik awal, dan_beginthreadex
dapat menggunakan salah satu__stdcall
atau__clrcall
untuk titik awal.Saya pikir setiap komentar yang dibuat orang mengenai kebocoran memori sudah
CreateThread
berusia lebih dari satu dekade dan mungkin harus diabaikan.Menariknya, kedua
_beginthread*
fungsi ini sebenarnya memanggil diCreateThread
bawah kap, diC:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src
pada mesin saya.sumber
beginthreadex
memberi Anda utasHANDLE
untuk digunakan dalamWaitForSingleObject
dan teman-teman.beginthread
tidak. Jangan lupaCloseHandle()
kapan Anda selesai. Jawaban sebenarnya adalah menggunakanboost::thread
atau segera kelas utas C ++ 09.sumber
Dibandingkan dengan
_beginthread
,_beginthreadex
Anda dapat:OpenThread
.CloseHandle
.Sangat
_beginthreadex
miripCreateThread
, tetapi yang pertama adalah implementasi CRT dan yang terakhir panggilan Windows API. Dokumentasi untuk CreateThread berisi rekomendasi berikut:sumber
_beginthreadex
. Anda dapatuintptr_t
mengembalikan dari kedua fungsi tersebut keHANDLE
._beginthread
menutup 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_beginthreadex
melakukannya untuk Anda.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) memanggilCreateThread()
tanpa melanggar CRT.Ini konfirmasi resmi MS . Ini menyatakan satu pengecualian:
Namun, dari sudut pandang konsistensi, saya pribadi lebih suka tetap menggunakan
_beginthreadex()
.sumber
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 sekitarCreateThread()
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.sumber
CreateThread()
adalah panggilan sistem langsung. Diimplementasikan diKernel32.dll
mana, 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 manipulasierrno
._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 menggunakanCreateThread()
, 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 bertahanCreateThread()
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.sumber
CreateThread
adalah 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 memanggilCreateThread
selain melakukan inisialisasi CRT yang diperlukan). Perbedaan paling penting antara_beginthread
dan varian sebelumnya: Yang pertama mempertahankan kepemilikan dari pegangan utas asli, sedangkan yang kedua meneruskan kepemilikan kepada penelepon.msvcrt.dll
adalah tidak C runtime DLL! Lihat blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273Jawaban 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*
dariDllMain
. Saya telah menguji ini dengan menulis DLL yang dimuat menggunakan fitur "AppInit_DLLs" Windows. Memanggil_beginthreadex (...)
alih-alihCreateThread (...)
menyebabkan BANYAK bagian penting Windows berhenti berfungsi saat bootup karenaDllMain
deadlock 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
DllMain
untuk menghindari situasi yang sama.sumber
Jika Anda membaca buku Debugging Windows Application Dari Jeffrey Richter di dalamnya, ia menjelaskan bahwa hampir dalam semua hal Anda harus menelepon
_beginthreadex
alih-alih meneleponCreateThread
._beginthread
hanyalah pembungkus sederhana di sekitar_beginthreadex
._beginthreadex
menginisialisasi internal CRT (C RunTime) tertentu yangCreateThread
tidak akan dilakukan API.Konsekuensi jika Anda menggunakan
CreateThread
API alih-alih menggunakan_begingthreadex
panggilan ke fungsi CRT dapat menyebabkan masalah yang tidak terduga.Lihat Microsoft Journal From Richter lama ini.
sumber
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.
sumber