_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, dan threadaddr. Utas baru dapat dibuat dalam status ditangguhkan, dengan keamanan tertentu, dan dapat diakses dengan menggunakan thrdaddr, 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 abortyang memanggil , , exit, _exitatau 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 = &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();
}

Tekan tombol apa pun untuk mengakhiri aplikasi sampel.

Kode sampel berikut menunjukkan bagaimana Anda dapat menggunakan handel utas yang dikembalikan oleh _beginthreadex dengan API WaitForSingleObjectsinkronisasi . Utas utama menunggu utas kedua dihentikan sebelum berlanjut. Ketika utas _endthreadexkedua 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