_beginthread, _beginthreadex

スレッドを作成します。

構文

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、呼び出し規約は (ネイティブ コードの場合) または __clrcall (マネージド コードの場合) です__cdecl。 の場合_beginthreadex、呼び出し規約は (ネイティブ コードの場合) または __clrcall (マネージド コードの場合) です__stdcall

stack_size
新しいスレッドのスタック サイズまたは 0。

arglist
新しいスレッドに渡される引数リストまたは NULL

Security
SECURITY_ATTRIBUTES 構造体へのポインター。この構造体は、返されたハンドルを子プロセスが継承できるかどうかを決定します。 存在NULLする場合Security、ハンドルを継承できません。

initflag
新しいスレッドの初期状態を制御するフラグ。 即時に実行するには initflag を 0 に設定し、一時停止状態でスレッドを作成するには CREATE_SUSPENDED に設定します。スレッドを実行するには、ResumeThread を使用します。 STACK_SIZE_PARAM_IS_A_RESERVATIONスタックの初期予約サイズとして使用stack_sizeするフラグをバイト単位で設定initflagします。このフラグが指定されていない場合は、stack_sizeコミット サイズを指定します。

thrdaddr
スレッド識別子を受け取る 32 ビット変数へのポインター。 NULL の場合は使用されません。

戻り値

成功すると、各関数は新しく作成されたスレッドのハンドルを返します。ただし、新しく作成されたスレッドの終了が早すぎる場合、 _beginthread は有効なハンドルを返さないことがあります (「解説」セクションの説明を参照してください)。エラーが発生した場合、_beginthread-1L を返しerrno、スレッドが多すぎる場合、引数が無効な場合、EINVALスタック サイズが正しくない場合、またはリソースが不足している場合 (メモリなど) にEACCES設定EAGAINされます。 エラーが発生すると、 _beginthreadex は 0 を返します。このとき errno_doserrno が設定されます。

有効な場合start_addressNULL、「パラメーターの検証」の説明に従って、無効なパラメーター ハンドラーが呼び出されます。 実行の継続が許可された場合、これらの関数は errnoEINVAL に設定し、-1 を返します。

これらのリターン コードとその他のリターン コードについては、「errno_doserrno_sys_errlist_sys_nerr」を参照してください。

詳細についてはuintptr_t、「標準型」を参照してください

解説

_beginthread 関数は、 start_addressで指定されるルーチンの実行を開始するスレッドを作成します。 start_address にあるルーチンは、 __cdecl (ネイティブ コードの場合) または __clrcall (マネージド コードの場合) の呼び出し規約を使用する必要があり、戻り値を持つことはできません。 スレッドがそのルーチンから戻ると、自動的に終了します。 スレッドの詳細については、「以前のコードのマルチスレッドサポート (Visual C++)」を参照してください

_beginthreadex は、_beginthread よりも Win32 CreateThread API に似ています。 _beginthreadex は、次の点が _beginthread とは異なります。

  • _beginthreadexには、次の 3 つのパラメーターがあります。 initflagSecuritythreadaddr セキュリティを指定し、一時停止状態で新しいスレッドを作成できます。新しいスレッドには、スレッド識別子 thrdaddrを使用してアクセスできます。

  • start_address に渡される _beginthreadex のルーチンは、__stdcall (ネイティブ コードの場合) または __clrcall (マネージド コードの場合) の呼び出し規約を使用する必要があり、スレッドの終了コードを返す必要があります。

  • _beginthreadex は、エラーの発生時に -1L ではなく 0 を返します。

  • _beginthreadex を使用して作成したスレッドは、_endthreadex の呼び出しで終了します。

_beginthreadex 関数は、スレッドの作成において _beginthread 関数よりも制御を詳細に行うことができます。 また、 _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 とは異なります。

Note

Libcmt.lib にリンクされている実行可能ファイルでは、Win32 の ExitThread API を呼び出さないでください。呼び出すと、割り当てられたリソースをランタイム システムで再利用することができなくなります。 _endthread_endthreadex は、割り当てられているスレッド リソースを解放し、 ExitThreadを呼び出します。

_beginthread または _beginthreadex が呼び出されると、オペレーティング システムがスタックの割り当てを処理します。したがって、スレッド スタックのアドレスをこれらの関数に渡す必要はありません。 また、引数 stack_size に 0 を指定すると、オペレーティング システムはメイン スレッドに対して指定したスタックと同じ値を使用します。

arglist は新しく作成したスレッドに渡すパラメーターです。 通常は、文字列などのデータ項目のアドレスです。 arglistNULL必要ないが、_beginthread_beginthreadex新しいスレッドに渡すために何らかの値を指定する必要がある場合です。 いずれかのスレッドが abortexit_exit、または ExitProcessを呼び出すと、すべてのスレッドが終了します。

新しいスレッドのロケールは、プロセスごとのグローバルな現在のロケール情報を使用して初期化されます。 _configthreadlocale の呼び出しにより、スレッドごとのロケールが (グローバルまたは新しいスレッドのみに対して) 有効になっている場合は、スレッドで setlocale または _wsetlocaleを呼び出すことで、そのスレッドのロケールを他のスレッドとは関係なく変更できます。 スレッドごとのロケール フラグが設定されていないスレッドは、スレッドごとのロケール フラグが設定されていない他のすべてのスレッドのロケール情報と、新しく作成されたすべてのスレッドに影響を与える可能性があります。 詳細については、「 Locale」を参照してください。

/clr コードについて、_beginthread_beginthreadex にはそれぞれ 2 つのオーバーロードが含まれます。 1 つはネイティブの呼び出し規約関数ポインターを受け取り、もう 1 つは __clrcall 関数ポインターを受け取ります。 最初のオーバーロードはアプリケーションで行うのではなくメイン安全であり、決して安全ではありません。 コードを記述/clrする場合は、新しいスレッドがマネージド リソースにアクセスする前にメイン正しいアプリケーションに入っていることを確認する必要があります。 たとえば、次のコマンドを使用 call_in_appdomainして行うことができます。 2 番目のオーバーロードはアプリケーション ドメイン セーフであり、新しく作成されたスレッドは、必ず _beginthread または _beginthreadexの呼び出し元のアプリケーション ドメインで終了します。

既定では、この関数のグローバル状態の適用対象は、アプリケーションになります。 この動作を変更するには、「CRT のグローバル状態」を参照してください

必要条件

ルーチンによって返される値 必須ヘッダー
_beginthread <process.h>
_beginthreadex <process.h>

互換性の詳細については、「 Compatibility」を参照してください。

ライブラリ

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

任意のキーを押してサンプル アプリケーションを終了します。

_beginthreadex から返されたスレッド ハンドルを同期 API WaitForSingleObject と共に使用する方法を次のサンプル コードで示します。 メイン スレッドは、2 番目のスレッドが終了するのを待って処理を継続します。 2 番目のスレッドが呼び出 _endthreadexされると、スレッド オブジェクトがシグナル状態になり、プライマリ スレッドの実行を続行できます。 呼び出しCloseHandle_endthreadは、シグナル状態に設定する前にスレッド オブジェクトを破棄するため_endthread、これを行うことはできません_beginthread

// 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

関連項目