_beginthread
, _beginthreadex
Membuat utas.
Sintaks
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthread( // MANAGED CODE
void( __clrcall *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthreadex( // NATIVE CODE
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
uintptr_t _beginthreadex( // MANAGED CODE
void *security,
unsigned stack_size,
unsigned ( __clrcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
Parameter
start_address
Alamat awal rutinitas yang memulai eksekusi utas baru. Untuk _beginthread
, konvensi panggilan adalah __cdecl
(untuk kode asli) atau __clrcall
(untuk kode terkelola). Untuk _beginthreadex
, konvensi panggilan adalah __stdcall
(untuk kode asli) atau __clrcall
(untuk kode terkelola).
stack_size
Ukuran tumpukan untuk utas baru, atau 0.
arglist
Daftar argumen yang akan diteruskan ke utas baru, atau NULL
.
Security
Penunjuk ke SECURITY_ATTRIBUTES
struktur yang menentukan apakah handel yang dikembalikan dapat diwariskan oleh proses anak. Jika Security
adalah NULL
, handel tidak dapat diwariskan.
initflag
Bendera yang mengontrol status awal utas baru. Atur initflag
ke 0 untuk segera berjalan, atau ke untuk CREATE_SUSPENDED
membuat utas dalam status ditangguhkan; gunakan ResumeThread
untuk menjalankan utas. Atur initflag
ke STACK_SIZE_PARAM_IS_A_RESERVATION
bendera untuk digunakan stack_size
sebagai ukuran cadangan awal tumpukan dalam byte; jika bendera ini tidak ditentukan, stack_size
tentukan ukuran penerapan.
thrdaddr
Menunjuk ke variabel 32-bit yang menerima pengidentifikasi utas. Jika itu NULL
, itu tidak digunakan.
Nilai hasil
Jika berhasil, masing-masing fungsi ini mengembalikan handel ke utas yang baru dibuat; namun, jika utas yang baru dibuat keluar terlalu cepat, _beginthread
mungkin tidak mengembalikan handel yang valid. (Lihat diskusi di bagian Keterangan.) Pada kesalahan, _beginthread
mengembalikan -1L, dan errno
diatur ke EAGAIN
jika ada terlalu banyak utas, ke EINVAL
jika argumen tidak valid atau ukuran tumpukan salah, atau jika EACCES
ada sumber daya yang tidak mencukupi (seperti memori). Pada kesalahan, _beginthreadex
mengembalikan 0, dan errno
dan _doserrno
diatur.
Jika start_address
adalah NULL
, handler parameter yang tidak valid dipanggil, seperti yang dijelaskan dalam Validasi parameter. Jika eksekusi diizinkan untuk melanjutkan, fungsi-fungsi ini diatur errno
ke EINVAL
dan mengembalikan -1.
Untuk informasi selengkapnya tentang kode pengembalian ini dan lainnya, lihat errno
, , _doserrno
_sys_errlist
, dan _sys_nerr
.
Untuk informasi selengkapnya tentang uintptr_t
, lihat Jenis standar.
Keterangan
Fungsi ini _beginthread
membuat utas yang memulai eksekusi rutinitas di start_address
. Rutinitas di start_address
harus menggunakan __cdecl
konvensi panggilan (untuk kode asli) atau __clrcall
(untuk kode terkelola) dan seharusnya tidak memiliki nilai pengembalian. Ketika utas kembali dari rutinitas tersebut, utas akan dihentikan secara otomatis. Untuk informasi selengkapnya tentang utas, lihat Dukungan multithreading untuk kode yang lebih lama (Visual C++).
_beginthreadex
menyerupai API Win32 CreateThread
lebih dekat daripada _beginthread
yang ada. _beginthreadex
berbeda dari _beginthread
dalam cara-cara berikut:
_beginthreadex
memiliki tiga parameter lagi:initflag
,Security
, danthreadaddr
. Utas baru dapat dibuat dalam status ditangguhkan, dengan keamanan tertentu, dan dapat diakses dengan menggunakanthrdaddr
, yang merupakan pengidentifikasi utas.Rutinitas pada yang diteruskan
start_address
untuk_beginthreadex
harus menggunakan__stdcall
konvensi panggilan (untuk kode asli) atau__clrcall
(untuk kode terkelola) dan harus mengembalikan kode keluar utas._beginthreadex
mengembalikan 0 pada kegagalan, bukan -1L.Utas yang dibuat dengan menggunakan
_beginthreadex
dihentikan oleh panggilan ke_endthreadex
.
Fungsi ini _beginthreadex
memberi Anda lebih banyak kontrol atas bagaimana utas dibuat daripada _beginthread
yang dilakukan. Fungsi _endthreadex
ini juga lebih fleksibel. Misalnya, dengan _beginthreadex
, Anda dapat menggunakan informasi keamanan, mengatur status awal utas (berjalan atau ditangguhkan), dan mendapatkan pengidentifikasi utas dari utas yang baru dibuat. Anda juga dapat menggunakan handel utas yang dikembalikan oleh _beginthreadex
dengan API sinkronisasi, yang tidak dapat Anda lakukan dengan _beginthread
.
_beginthreadex
lebih aman untuk digunakan daripada _beginthread
. Jika utas yang dihasilkan oleh _beginthread
keluar dengan cepat, handel yang dikembalikan ke pemanggil _beginthread
mungkin tidak valid atau menunjuk ke utas lain. Namun, handel yang dikembalikan oleh _beginthreadex
harus ditutup oleh pemanggil _beginthreadex
, sehingga dijamin akan menjadi handel yang valid jika _beginthreadex
tidak mengembalikan kesalahan.
Anda dapat memanggil _endthread
atau _endthreadex
secara eksplisit untuk mengakhiri utas; namun, _endthread
atau _endthreadex
dipanggil secara otomatis ketika utas kembali dari rutinitas yang diteruskan sebagai parameter. Mengakhiri utas dengan panggilan ke _endthread
atau _endthreadex
membantu memastikan pemulihan sumber daya yang benar yang dialokasikan untuk utas.
_endthread
secara otomatis menutup handel utas, sedangkan _endthreadex
tidak. Oleh karena itu, ketika Anda menggunakan _beginthread
dan _endthread
, jangan secara eksplisit menutup handel utas dengan memanggil API Win32 CloseHandle
. Perilaku ini berbeda dari API Win32 ExitThread
.
Catatan
Untuk file yang dapat dieksekusi yang ditautkan dengan Libcmt.lib, jangan panggil API Win32 ExitThread
sehingga Anda tidak mencegah sistem run-time mengklaim kembali sumber daya yang dialokasikan. _endthread
dan _endthreadex
klaim kembali sumber daya utas yang dialokasikan lalu panggil ExitThread
.
Sistem operasi menangani alokasi tumpukan saat _beginthread
atau _beginthreadex
dipanggil; Anda tidak perlu meneruskan alamat tumpukan utas ke salah satu fungsi ini. Selain itu, stack_size
argumen bisa 0, dalam hal ini sistem operasi menggunakan nilai yang sama dengan tumpukan yang ditentukan untuk utas utama.
arglist
adalah parameter yang akan diteruskan ke utas yang baru dibuat. Biasanya, ini adalah alamat item data, seperti string karakter. arglist
bisa jadi NULL
jika tidak diperlukan, tetapi _beginthread
dan _beginthreadex
harus diberi beberapa nilai untuk diteruskan ke utas baru. Semua utas dihentikan jika ada utas abort
yang memanggil , , exit
, _exit
atau ExitProcess
.
Lokal utas baru diinisialisasi dengan menggunakan info lokal global saat ini per proses. Jika lokal per utas diaktifkan oleh panggilan ke _configthreadlocale
(baik secara global atau hanya untuk utas baru), utas dapat mengubah lokalnya secara independen dari utas lain dengan memanggil setlocale
atau _wsetlocale
. Rangkaian yang tidak memiliki set bendera lokal per utas dapat memengaruhi info lokal di semua utas lain yang juga tidak memiliki set bendera lokal per utas, dan juga semua utas yang baru dibuat. Untuk informasi selengkapnya, lihat Lokal.
Untuk /clr
kode, _beginthread
dan _beginthreadex
masing-masing memiliki dua kelebihan beban. Satu mengambil penunjuk fungsi konvensi panggilan asli, dan yang lain mengambil __clrcall
penunjuk fungsi. Kelebihan beban pertama bukan domain aplikasi yang aman dan tidak akan pernah. Jika Anda menulis /clr
kode, Anda harus memastikan bahwa utas baru memasuki domain aplikasi yang benar sebelum mengakses sumber daya terkelola. Anda dapat melakukannya, misalnya, dengan menggunakan call_in_appdomain
. Kelebihan beban kedua adalah domain aplikasi yang aman; utas yang baru dibuat akan selalu berakhir di domain aplikasi pemanggil _beginthread
atau _beginthreadex
.
Secara default, status global fungsi ini dicakup ke aplikasi. Untuk mengubah perilaku ini, lihat Status global di CRT.
Persyaratan
Rutin | Header yang diperlukan |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Untuk informasi kompatibilitas selengkapnya, lihat Kompatibilitas.
Pustaka
Versi multithreaded pustaka run-time C saja.
Untuk menggunakan _beginthread
atau _beginthreadex
, aplikasi harus ditautkan dengan salah satu pustaka run-time C multithreaded.
Contoh
Contoh berikut menggunakan _beginthread
dan _endthread
.
// crt_BEGTHRD.C
// compile with: /MT /D "_X86_" /c
// processor: x86
#include <windows.h>
#include <process.h> /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
void Bounce( void * );
void CheckKey( void * );
// GetRandom returns a random integer between min and max.
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
// GetGlyph returns a printable ASCII character value
#define GetGlyph( val ) ((char)((val + 32) % 93 + 33))
BOOL repeat = TRUE; // Global repeat flag
HANDLE hStdOut; // Handle for console window
CONSOLE_SCREEN_BUFFER_INFO csbi; // Console information structure
int main()
{
int param = 0;
int * pparam = ¶m;
// Get display screen's text row and column information.
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleScreenBufferInfo( hStdOut, &csbi );
// Launch CheckKey thread to check for terminating keystroke.
_beginthread( CheckKey, 0, NULL );
// Loop until CheckKey terminates program or 1000 threads created.
while( repeat && param < 1000 )
{
// launch another character thread.
_beginthread( Bounce, 0, (void *) pparam );
// increment the thread parameter
param++;
// Wait one second between loops.
Sleep( 1000L );
}
}
// CheckKey - Thread to wait for a keystroke, then clear repeat flag.
void CheckKey( void * ignored )
{
_getch();
repeat = 0; // _endthread implied
}
// Bounce - Thread to create and control a colored letter that moves
// around on the screen.
//
// Params: parg - the value to create the character from
void Bounce( void * parg )
{
char blankcell = 0x20;
CHAR_INFO ci;
COORD oldcoord, cellsize, origin;
DWORD result;
SMALL_RECT region;
cellsize.X = cellsize.Y = 1;
origin.X = origin.Y = 0;
// Generate location, letter and color attribute from thread argument.
srand( _threadid );
oldcoord.X = region.Left = region.Right =
GetRandom(csbi.srWindow.Left, csbi.srWindow.Right - 1);
oldcoord.Y = region.Top = region.Bottom =
GetRandom(csbi.srWindow.Top, csbi.srWindow.Bottom - 1);
ci.Char.AsciiChar = GetGlyph(*((int *)parg));
ci.Attributes = GetRandom(1, 15);
while (repeat)
{
// Pause between loops.
Sleep( 100L );
// Blank out our old position on the screen, and draw new letter.
WriteConsoleOutputCharacterA(hStdOut, &blankcell, 1, oldcoord, &result);
WriteConsoleOutputA(hStdOut, &ci, cellsize, origin, ®ion);
// Increment the coordinate for next placement of the block.
oldcoord.X = region.Left;
oldcoord.Y = region.Top;
region.Left = region.Right += GetRandom(-1, 1);
region.Top = region.Bottom += GetRandom(-1, 1);
// Correct placement (and beep) if about to go off the screen.
if (region.Left < csbi.srWindow.Left)
region.Left = region.Right = csbi.srWindow.Left + 1;
else if (region.Right >= csbi.srWindow.Right)
region.Left = region.Right = csbi.srWindow.Right - 2;
else if (region.Top < csbi.srWindow.Top)
region.Top = region.Bottom = csbi.srWindow.Top + 1;
else if (region.Bottom >= csbi.srWindow.Bottom)
region.Top = region.Bottom = csbi.srWindow.Bottom - 2;
// If not at a screen border, continue, otherwise beep.
else
continue;
Beep((ci.Char.AsciiChar - 'A') * 100, 175);
}
// _endthread given to terminate
_endthread();
}
Tekan tombol apa pun untuk mengakhiri aplikasi sampel.
Kode sampel berikut menunjukkan bagaimana Anda dapat menggunakan handel utas yang dikembalikan oleh _beginthreadex
dengan API WaitForSingleObject
sinkronisasi . Utas utama menunggu utas kedua dihentikan sebelum berlanjut. Ketika utas _endthreadex
kedua memanggil , itu menyebabkan objek utasnya masuk ke status yang disinyalir, yang memungkinkan utas utama untuk terus berjalan. Ini tidak dapat dilakukan dengan _beginthread
dan _endthread
, karena _endthread
panggilan CloseHandle
, yang menghancurkan objek utas sebelum dapat diatur ke status yang disinyalir.
// crt_begthrdex.cpp
// compile with: /MT
#include <windows.h>
#include <stdio.h>
#include <process.h>
unsigned Counter;
unsigned __stdcall SecondThreadFunc( void* pArguments )
{
printf( "In second thread...\n" );
while ( Counter < 1000000 )
Counter++;
_endthreadex( 0 );
return 0;
}
int main()
{
HANDLE hThread;
unsigned threadID;
printf( "Creating second thread...\n" );
// Create the second thread.
hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );
// Wait until second thread terminates. If you comment out the line
// below, Counter will not be correct because the thread has not
// terminated, and Counter most likely has not been incremented to
// 1000000 yet.
WaitForSingleObject( hThread, INFINITE );
printf( "Counter should be 1000000; it is-> %d\n", Counter );
// Destroy the thread object.
CloseHandle( hThread );
}
Creating second thread...
In second thread...
Counter should be 1000000; it is-> 1000000
Baca juga
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk