共用方式為


_beginthread、_beginthreadex

建立執行緒。

重要

這個應用程式開發介面無法在執行於 Windows 執行階段的應用程式或使用 clr:pure 參數所編譯的應用程式中使用。如需詳細資訊,請參閱 /ZW 不支援 CRT 函式

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 (若為 Managed 程式碼)。對於 _beginthreadex,則是 __stdcall (若為機器碼) 或 __clrcall (若為 Managed 程式碼)。

  • stack_size
    新執行緒堆疊大小或 0。

  • arglist
    要傳遞給新執行緒的參數清單或 NULL。

  • Security
    SECURITY ATTRIBUTES 結構的指標,這個結構會判斷子處理程序是否可以繼承傳回的控制代碼。 如果 Security 為 NULL,則無法繼承控制代碼。 對於 Windows 95 應用程式必須是 NULL。

  • initflag
    控制新執行緒之初始狀態的旗標。 將 initflag 設定為 0 以立即執行,或是設定為 CREATE_SUSPENDED 以建立暫停狀態的執行緒;請使用 ResumeThread (英文) 執行執行緒。 將 initflag 設定為 STACK_SIZE_PARAM_IS_A_RESERVATION 旗標以使用 stack_size 作為堆疊的初始預留大小 (以位元組為單位)。若未指定此旗標,stack_size 會指定基本配置大小。

  • thrdaddr
    指向接收執行緒識別項的 32 位元變數。 如果是 NULL,則不使用它。

傳回值

如果成功,則每一個這些函式都會將控制代碼傳回至新建立的執行緒。然而,如果新建立的執行緒太快結束,_beginthread 可能無法傳回有效的控制代碼 (請參閱<備註>一節中的討論)。發生錯誤時,_beginthread 會傳回 -1L。此時的 errno,如果是有太多的執行緒則設為 EAGAIN,如果是引數不合法或堆疊大小不正確則設為 EINVAL,如果是資源不足 (例如記憶體) 則設為EACCES。 發生錯誤時,_beginthreadex 會傳回 0,並設定 errno 和 _doserrno。

如果 startaddress 為 NULL,則會叫用無效參數處理常式,如參數驗證中所述。 如果允許繼續執行,這些函式會將 errno 設為 EINVAL,並傳回 -1。

如需有關這些傳回碼和其他傳回碼的詳細資訊,請參閱 errno、_doserrno、_sys_errlist 和 _sys_nerr

如需 uintptr_t 的詳細資訊,請參閱 標準類型

備註

_beginthread 函式會建立一個從 start_address 開始執行常式的執行緒。 在 start_address 的常式必須使用 __cdecl (若為機器碼) 或 __clrcall (若為 Managed 程式碼) 呼叫慣例,而且不應該有傳回值。 執行緒從該常式返回時,就會自動終止。 如需執行緒的詳細資訊,請參閱舊版程式碼的多執行緒支援 (Visual C++)

相較於 _beginthread 的行為,_beginthreadex 更類似 Win32 CreateThread (英文) API。 _beginthreadex 與 _beginthread 在下列各方面不同:

  • _beginthreadex 有三個額外的參數:initflag、security 和 threadaddr。 新執行緒可以使用指定的安全性建立在暫停狀態,並且可以使用執行緒識別項 thrdaddr 來加以存取。

  • 位於傳遞至 _beginthreadex 之 start_address 的常式必須使用 __stdcall (若為機器碼) 或 __clrcall (若為 Managed 程式碼) 呼叫慣例,而且必須傳回執行緒結束代碼。

  • _beginthreadex 會在失敗時回傳 0,而非 -1L。

  • 使用 _beginthreadex 建立的執行緒,是藉由對 _endthreadex 的呼叫來結束。

比起 _beginthread,_beginthreadex 函式給予您更多掌控執行緒建立方式的能力。 _endthreadex 函式也更有彈性。 例如,您可以透過 _beginthreadex,使用安全性資訊、設定執行緒初始狀態 (執行或暫停),以及取得新建立執行緒的執行緒識別項。 您也可以搭配同步處理應用程式開發介面來使用 _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 應用程式開發介面,這樣才不會阻止執行階段系統回收配置的資源。_endthread 和 _endthreadex 會回收配置的執行緒資源,然後呼叫 ExitThread。

呼叫 _beginthread 或 _beginthreadex 時,作業系統會處理堆疊的配置,您不必將執行緒堆疊的位址傳遞給這兩個函式。 此外,stack_size 參數也可以為 0,此時作業系統會使用的值與指定給主執行緒的堆疊相同。

arglist 是要傳遞給新建立執行緒的參數。 這通常是資料項目的位址,例如字元字串。 arglist 在不需要時可以為 NULL,但是 _beginthread 和 _beginthreadex 必須有某個指定的值,才能傳遞給新的執行緒。 如果有任何執行緒呼叫 abort、exit、_exit 或 ExitProcess,就會結束所有的執行緒。

新執行緒的地區設定是從父執行緒繼承而來。 如果透過呼叫 _configthreadlocale (以全域方式或只針對新執行緒) 啟用個別執行緒地區設定,則執行緒可以呼叫 setlocale 或 _wsetlocale,在父執行緒之外獨立變更其地區設定。 如需詳細資訊,請參閱地區設定

對於混合程式碼或純程式碼,_beginthread 和 _beginthreadex 各有兩種多載版本,一個接受原生呼叫慣例函式指標,另一個接受 __clrcall 函式指標。 第一個多載不是應用程式定義域安全的,而且永遠不會是。 如果您要撰寫混合程式碼或純程式碼,就必須確保新的執行緒會在存取 Managed 資源前進入正確的應用程式定義域。 例如,您可以使用 call_in_appdomain 函式 來達成這個目的。 第二個多載版本是應用程式定義域安全的。新建立的執行緒永遠都會在 _beginthread 或 _beginthreadex 呼叫端的應用程式定義域中結束。

需求

常式

必要的標頭

_beginthread

<process.h>

_beginthreadex

<process.h>

如需詳細的相容性資訊,請參閱相容性

程式庫

僅限 C 執行階段程式庫的多執行緒版本。

若要使用 _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 * );
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 = &param;

    // 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 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, &region);

        // 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();
}

按下任意鍵結束範例應用程式。

下列範例程式碼示範如何搭配同步處理 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

請參閱

參考

流程控制和環境控制

_endthread、_endthreadex

abort

exit、_exit

GetExitCodeThread