_beginthread _beginthreadex
建立執行緒。
重要
這個 API 不能用於 Windows 執行階段執行的應用程式。如需詳細資訊,請參閱 CRT 函式不支援使用 /ZW。
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
);
參數
start_address
啟動新執行緒的執行常式的開始位址。 對於 _beginthread ,呼叫慣例是 __cdecl (若為本地碼) 或 __clrcall (若為管理碼) 。對於 _beginthreadex ,它是 __stdcall (對於本地碼) 或 __clrcall (對於管理碼) 。stack_size
新執行緒的堆疊大小或 0 。Arglist
傳入新的執行緒的參數清單或空。Security
指向 SECURITY ATTRIBUTES 結構的指標,用以判斷回傳的處理常式是否可以被子處理程序繼承。 若為空,處理常式無法被繼承。 它對於 Windows 95 應用程式必為空。Initflag
新的執行緒的初始狀態 (0 為執行, CREATE_SUSPENDED 為暫停) 。使用 ResumeThread 來執行執行緒。Thrdaddr
指向接受執行緒識別項的 32 位元變數。 可能為 NULL ,此時它不被使用。
傳回值
若成功,每一個這些函式回傳處理常式予新建立的執行緒。然後,如果新建立的執行緒過快離開, _beginthread 可能不會回傳有效的處理常式 (請參閱 Remarks 一節的討論) 。 _beginthread 在發生錯誤時回傳 -1L ,此時 errno 在太多執行緒時會被設置為 EAGAIN ,在參數不合法或堆疊大小不正確會被設置為 EINVAL ,或在資源不足時 (例如記憶體) 被設置為 EACCES 。 _beginthreadex 在發生錯誤時回傳 0 ,此時 errno 和 _doserrno 會被設置。
如果 startaddress 是 NULL ,無效參數處理常式會被調用,如 參數驗證 中所述。 如果允許繼續執行,這些函式將 EINVAL 設置為 errno 並回傳 -1 。
如需更多關於這些和其他回傳碼的資訊,請參閱 _doserrno 、 errno 、 _sys_errlist 、和 _sys_nerr (_doserrno, errno, _sys_errlist, and _sys_nerr) 。
如需更多關於 uintptr_t 的資訊,請參閱 標準型別 (Standard Types) 。
備註
_beginthread 函式建立一個執行緒在 start_address 開始執行一個常式。 在 start_address 的常式必須使用 __cdecl (若為本地碼) 或 __clrcall (若為管理碼) 的呼叫慣例並不該有回傳值。 當執行緒從該常式結束,它會自動終止。 如需執行緒模型的詳細資訊,請參閱 多執行緒 (Multithreading)。
_beginthreadex 重新組合 Win32 CreateThread API 得比 _beginthread 更緊密。 _beginthreadex 與 _beginthread 在以下方面不同:
_beginthreadex 擁有三個額外的參數: initflag 、 security 和 threadaddr 。 新的執行緒可以以指定的安全性 (只有在 Windows NT) 下建立為暫停狀態,並且可以使用執行緒識別項 thrdaddr 存取。
在 start_address ,傳入 _beginthreadex 的常式必須使用 __stdcall (若為本地碼) 或 __clrcall (若為管理碼) 呼叫慣例並且必須回傳一個執行緒終止碼。
_beginthreadex 在失敗時回傳 0 ,而非 -1L 。
以 _beginthreadex 建立的執行緒會藉由呼叫 _endthreadex 終止。
比起 _beginthread , _beginthreadex 函式給予您更多執行緒建立方式的控制。 _endthreadex 函式也更有彈性。 例如, 使用 _beginthreadex 時,您可以使用安全性資訊,設置執行緒的初始狀態 (執行或暫停) ,並取得新建立的執行緒的執行緒識別項。 您也可以與同步化的 API 使用 _beginthreadex回傳的執行緒處理常式,這在 _beginthread 裏是辦不到的。
使用 _beginthreadex 也比起 _beginthread 更為安全。 如果 _beginthread 所產生的執行緒結束得過快,回傳給 _beginthread 呼叫者的處理常式可能會無效,或在更糟的情況下可能指向其他的執行緒。 然而, _beginthreadex 回傳的處理常式必須由 _beginthreadex 的呼叫者關閉,如此可保證 _beginthreadex 不回傳錯誤時是有效的處理常式。
您可以顯示地呼叫 _endthread 或 _endthreadex 來終止執行緒。然而,常式結束的執行緒以參數傳入時 _endthread 或 endthreadex 會被呼叫。 以呼叫 endthread 或 _endthreadex 終止執行緒將有助於確保分配予執行緒的資源能妥善的回覆。
_endthread 自動關閉執行緒處理常式 (而 _endthreadex 不會) 。 因此,當使用 _beginthread 和 _endthread 時,請勿藉由呼叫 Win32 CloseHandle API 來顯示地關閉執行緒處理常式。 這個行為與 Win32 ExitThread API 不同。
注意事項 |
---|
對於與 Libcmt.lib 連結的可執行檔,請勿呼叫 Win32 ExitThread API 。如此以避免執行階段系統重覆宣告配置的資源。_endthread 和 _endthreadex 重新宣告配置的執行緒資源然後呼叫 ExitThread 。 |
作業系統處在 _beginthread 或 _beginthreadex 被呼叫時處理堆疊的配置。請您不必傳入執行緒的堆疊位址到這兩個函式裏。 此外, stack_size 參數可以為 0 ,此時作業系統使用與主執行緒相同的堆疊大小。
arglist 是被傳入新建立的執行緒的參數。 通常這是資料項目的位址,例如字元字串。 arglist 在不需要時可以為 NULL ,但 _beginthread 和 _beginthreadex 必須提供一些值予新執行緒。 如果任何執行緒呼叫 abort 、 exit 、 _exit 或 ExitProcess 時所有的執行緒會被終止。
新的執行緒的地區設定是從父執行緒繼承而來。 如果透過呼叫 _configthreadlocale 來啟用執行緒個別套用地區設定 (全域性或只有新的執行緒) ,執行緒可以透過呼叫 setlocale 或 _wsetlocale 從其父執行緒獨立地改變它的地區設定。 如需詳細資訊,請參閱 地區設定 (Locale) 。
對於混合或純粹的程式碼, _beginthread 和 _beginthreadex 均有兩種多載版本,其一接受本地呼叫慣例函式指標,另一接受 __clrcall 函式指標。 第一個多載版本不會且永遠不會是應用程式域安全的。 如果您撰寫混合或純粹程式碼,您必須確保新的執行緒在存取管理資源前進入正確的應用程式域。 例如,您可以透過使用 call_in_appdomain 函式 來達成。 第二個多載版本是應用程式域安全的。新建立的執行緒會永遠在 _beginthread 或 _beginthreadex 的呼叫者的應用程式域結束。
需求
程序 |
必要的標頭檔 |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
如需更多關於相容性的資訊,請參閱入門介紹中的 相容性 (Compatibility) 。
程式庫
僅於 C 執行階段程式庫 (C run-time libraries) 的多執行緒版本。
若要使用 _beginthread 或 _beginthreadex,應用程式必須使用其中一個多執行緒 C 執行階段程式庫的連結。
範例
下列的範例會使用 _beginthread 和 _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 *ch );
void CheckKey( void *dummy );
/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
BOOL repeat = TRUE; /* Global repeat flag and video variable */
HANDLE hStdOut; /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* Console information structure */
int main()
{
CHAR ch = 'A';
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
/* Get display screen's text row and column information. */
GetConsoleScreenBufferInfo( hStdOut, &csbi );
/* Launch CheckKey thread to check for terminating keystroke. */
_beginthread( CheckKey, 0, NULL );
/* Loop until CheckKey terminates program. */
while( repeat )
{
/* On first loops, launch character threads. */
_beginthread( Bounce, 0, (void *) (ch++) );
/* Wait one second between loops. */
Sleep( 1000L );
}
}
/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
_getch();
repeat = 0; /* _endthread implied */
}
/* Bounce - Thread to create and and control a colored letter that moves
* around on the screen.
* Params: ch - the letter to be moved
*/
void Bounce( void *ch )
{
/* Generate letter and color attribute from thread argument. */
char blankcell = 0x20;
char blockcell = (char) ch;
BOOL first = TRUE;
COORD oldcoord, newcoord;
DWORD result;
/* Seed random number generator and get initial location. */
srand( _threadid );
newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
while( repeat )
{
/* Pause between loops. */
Sleep( 100L );
/* Blank out our old position on the screen, and draw new letter. */
if( first )
first = FALSE;
else
WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );
/* Increment the coordinate for next placement of the block. */
oldcoord.X = newcoord.X;
oldcoord.Y = newcoord.Y;
newcoord.X += GetRandom( -1, 1 );
newcoord.Y += GetRandom( -1, 1 );
/* Correct placement (and beep) if about to go off the screen. */
if( newcoord.X < 0 )
newcoord.X = 1;
else if( newcoord.X == csbi.dwSize.X )
newcoord.X = csbi.dwSize.X - 2;
else if( newcoord.Y < 0 )
newcoord.Y = 1;
else if( newcoord.Y == csbi.dwSize.Y )
newcoord.Y = csbi.dwSize.Y - 2;
/* If not at a screen border, continue, otherwise beep. */
else
continue;
Beep( ((char) ch - 'A') * 100, 175 );
}
/* _endthread given to terminate */
_endthread();
}
press any key to end
下列範例程式碼展示您如何與同步化 API WaitForSingleObject 使用 _beginthreadex 回傳的執行緒處理常式。 主執行緒在繼續執行以前等待第二個執行緒的終止。 在第二個執行緒呼叫 _endthreadex 時,它會讓它的執行緒物件移至已收到信號的狀態。 這樣可讓主執行緒繼續執行。 這無法透過 _beginthread 和 _endthread 來達成。因為 _endthread 呼叫 CloseHandle ,在它可以被設置為已收到信號狀態前便已被解構。
// 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 );
}
.NET Framework 對等用法
System::Threading::Thread::Start