Monday, May 16, 2011

Windows Thread programming example

This example code shows how to write a mutli-thread application using Windows thread APIs. The thread functions provided by win32 API is almost the same as pthread package. (Actually, pthread package is recommended instead of windows thread APIs). Following example uses CreateThread() function to create threads and
WaitForMultipleObjects() to wait threads to finish and CloseHandle() to destroy
Thread handles. [Windows thread programming example]

#include <windows.h>  
#include <tchar.h>  
#include <strsafe.h>  
  
#define MAX_THREADS 3  
#define BUF_SIZE 255  
  
DWORD WINAPI MyThreadFunction( LPVOID lpParam );  
void ErrorHandler(LPTSTR lpszFunction);  
  
/*  
  User data for threads.
 */  
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++ )  
    {  
        pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  
                sizeof(MYDATA));  
  
        if( pDataArray[i] == NULL )  
        {  
            ExitProcess(2);  
        }  
  
        // Set parameters to the threads.
        pDataArray[i]->val1 = i;  
        pDataArray[i]->val2 = i+100;  
  
        // Create thread.
        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   
   
        if (hThreadArray[i] == NULL)   
        {  
           ErrorHandler(TEXT("CreateThread"));  
           ExitProcess(3);  
        }  
    }  
  
    // Wait for the thread to finish.
//  
    WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);  
  
    // Close all thread handles and reclaim memory.
//
    for(int i=0; i<MAX_THREADS; i++)  
    {  
        CloseHandle(hThreadArray[i]);  
        if(pDataArray[i] != NULL)  
        {  
            HeapFree(GetProcessHeap(), 0, pDataArray[i]);  
            pDataArray[i] = NULL;   
        }  
    }  
  
    return 0;  
}  
  
  
// Main Thread Function.
DWORD WINAPI MyThreadFunction( LPVOID lpParam )   
{   
    HANDLE hStdout;  
    PMYDATA pDataArray;  
  
    TCHAR msgBuf[BUF_SIZE];  
    size_t cchStringSize;  
    DWORD dwChars;  
  
    
    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(LPTSTR 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);  
}