Aracılığıyla paylaş


İş Parçacıkları Oluşturma

CreateThread işlevi bir işlem için yeni bir iş parçacığı oluşturur. Oluşturma iş parçacığı, yeni iş parçacığının yürütülecek kodun başlangıç adresini belirtmelidir. Genellikle, başlangıç adresi program kodunda tanımlanan bir işlevin adıdır (daha fazla bilgi için bkz. ThreadProc). Bu işlev tek bir parametre alır ve bir DWORD değeri döndürür. Bir işlemin aynı işlevi aynı anda yürüten birden çok iş parçacığı olabilir.

Aşağıda, MyThreadFunctionyerel olarak tanımlanan işlevi yürüten yeni bir iş parçacığının nasıl oluşturulacağını gösteren basit bir örnek verilmiştir.

Çağıran iş parçacığı, tüm çalışan iş parçacıkları sonlandırılana kadar kalıcı olmak için waitformultipleObjectsişlevini kullanır. Çağrı iş parçacığı beklerken bloklanır; işlemeye devam etmek için çağrı iş parçacığı WaitForSingleObject kullanır ve her bir çalışan iş parçacığının bekleme nesnesini işaret etmesini bekler. İş parçacığı sonlandırılmadan önce tanıtıcıyı bir çalışan iş parçacığına kapatırsanız, bunun çalışan iş parçacığını sonlandırmadığını unutmayın. Ancak tanıtıcı sonraki işlev çağrılarında kullanılamaz.

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#define MAX_THREADS 3
#define BUF_SIZE 255

DWORD WINAPI MyThreadFunction( LPVOID lpParam );
void ErrorHandler(LPCTSTR lpszFunction);

// Sample custom data structure for threads to use.
// This is passed by void pointer so it can be any data type
// that can be passed using a single void pointer (LPVOID).
typedef struct MyData {
    int val1;
    int val2;
} MYDATA, *PMYDATA;


int _tmain()
{
    PMYDATA pDataArray[MAX_THREADS];
    DWORD   dwThreadIdArray[MAX_THREADS];
    HANDLE  hThreadArray[MAX_THREADS]; 

    // Create MAX_THREADS worker threads.

    for( int i=0; i<MAX_THREADS; i++ )
    {
        // Allocate memory for thread data.

        pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                sizeof(MYDATA));

        if( pDataArray[i] == NULL )
        {
           // If the array allocation fails, the system is out of memory
           // so there is no point in trying to print an error message.
           // Just terminate execution.
            ExitProcess(2);
        }

        // Generate unique data for each thread to work with.

        pDataArray[i]->val1 = i;
        pDataArray[i]->val2 = i+100;

        // Create the thread to begin execution on its own.

        hThreadArray[i] = CreateThread( 
            NULL,                   // default security attributes
            0,                      // use default stack size  
            MyThreadFunction,       // thread function name
            pDataArray[i],          // argument to thread function 
            0,                      // use default creation flags 
            &dwThreadIdArray[i]);   // returns the thread identifier 


        // Check the return value for success.
        // If CreateThread fails, terminate execution. 
        // This will automatically clean up threads and memory. 

        if (hThreadArray[i] == NULL) 
        {
           ErrorHandler(TEXT("CreateThread"));
           ExitProcess(3);
        }
    } // End of main thread creation loop.

    // Wait until all threads have terminated.

    WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);

    // Close all thread handles and free memory allocations.

    for(int i=0; i<MAX_THREADS; i++)
    {
        CloseHandle(hThreadArray[i]);
        if(pDataArray[i] != NULL)
        {
            HeapFree(GetProcessHeap(), 0, pDataArray[i]);
            pDataArray[i] = NULL;    // Ensure address is not reused.
        }
    }

    return 0;
}


DWORD WINAPI MyThreadFunction( LPVOID lpParam ) 
{ 
    HANDLE hStdout;
    PMYDATA pDataArray;

    TCHAR msgBuf[BUF_SIZE];
    size_t cchStringSize;
    DWORD dwChars;

    // Make sure there is a console to receive output results. 

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    if( hStdout == INVALID_HANDLE_VALUE )
        return 1;

    // Cast the parameter to the correct data type.
    // The pointer is known to be valid because 
    // it was checked for NULL before the thread was created.
 
    pDataArray = (PMYDATA)lpParam;

    // Print the parameter values using thread-safe functions.

    StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"), 
        pDataArray->val1, pDataArray->val2); 
    StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
    WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);

    return 0; 
} 



void ErrorHandler(LPCTSTR lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code.

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message.

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK); 

    // Free error-handling buffer allocations.

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

MyThreadFunction işlevi C çalışma zamanı kitaplığının (CRT) kullanılmasını önler, ancak işlevlerin çoğu iş parçacığı açısından güvenli değildir, özellikle de çok iş parçacıklı CRT kullanmıyorsanız. CRT'yi bir ThreadProc işlevinde kullanmak istiyorsanız bunun yerine _beginthreadex işlevini kullanın.

İşaretçi geçersiz hale geldiğinden, oluşturma iş parçacığı yeni iş parçacığından önce çıkarsa yerel değişkenin adresini geçirmek risklidir. Bunun yerine, dinamik olarak ayrılan belleğe bir işaretçi geçirin veya oluşturma iş parçacığının yeni iş parçacığının sonlandırılması için beklemesini sağlayın. Veriler oluşturma iş parçacığından genel değişkenler kullanılarak yeni iş parçacığına da geçirilebilir. Genel değişkenlerle, genellikle erişimi birden fazla iş parçacığı tarafından eşitlemek gerekir. Senkronizasyon hakkında daha fazla bilgi için bkz. Birden Çok İş Parçacığının Yürütülmesini Senkronize Etme.

Oluşturma iş parçacığı, aşağıdakileri belirtmek üzere CreateThread için bağımsız değişkenleri kullanabilir.

  • Yeni iş parçacığı tanıtıcısının güvenlik öznitelikleri. Bu güvenlik öznitelikleri, tanıtıcının alt işlemler tarafından devralınıp devralınamayacağını belirleyen bir devralma bayrağı içerir. Güvenlik öznitelikleri, sistemin erişim verilmeden önce iş parçacığı tanıtıcısının tüm sonraki kullanımlarında erişim denetimleri gerçekleştirmesi için kullandığı bir güvenlik tanımlayıcısı da içerir.
  • Yeni iş parçacığının ilk yığın boyutu. İş parçacığının yığını işlemin bellek alanına otomatik olarak ayrılır; sistem, yığını gerektiği gibi artırır ve iş parçacığı sonlandırıldığında bu yığını serbestleştirir. Daha fazla bilgi için bkz. İş Parçacığı Yığılma Boyutu.
  • Askıda oluşturmanıza olanak tanıyan bir oluşturma bayrağı. Askıya aldığınızda, ResumeThread işlevi çağrılana kadar iş parçacığı çalışmaz.

CreateRemoteThread işlevini çağırarak da iş parçacığı oluşturabilirsiniz. Bu işlev, hata ayıklayıcı işlemleri tarafından hata ayıklanan işlemin adres alanında çalışan bir iş parçacığı oluşturmak için kullanılır.

Bir İş Parçacığını Sonlandırma