Feb 2, 2011

Multithreading in Windows - A simple example

A thread is an independent unit of execution within a process. Threads under windows can be created/terminated using the following Win API functions:

1. CreateThread()/ExitThread() system calls.
2. _beginthread()/_endthread() OR _beginthreadex()/_endthreadex() CRT functions.

Key Points

1. Using CreateThread() in a program that uses the CRT functions (for example, links with LIBCMT.LIB) may cause a memory leak of about 70-80 bytes each time a thread is terminated.
2. _beginthread()/_endthread() CRT functions provide a simpler interface but should be avoided. _beginthread() does not have a security attribute, and does not return a thread id. More importantly, it closes the handle of the thread it creates, and the returned thread handle may be invalid by the time the parent thread stores it. If the thread spawned by _beginthread() exits quickly, the handle returned to the caller of _beginthread() may be invalid or, worse, point to another thread. Also avoid _endthread() it does not allow for a return value.
3. With _beginthreadex(), you can use security information, set the initial state of the thread (running or suspended), and get the thread identifier of the newly created thread. You are also able to use the thread handle returned by _beginthreadex() with the synchronization APIs.
4. _endthread() or _endthreadex() is called automatically when the thread returns from the routine passed as a parameter

The example code creates three independent threads using _beginthreadex() in suspended state scheduled to run for 10, 20 & 30 seconds. The threads resume execution after the call to ResumeThread(). The WaitForSingleObject() waits for the given thread for passed slice of time. The function returns with value 0 if the thread terminates by self and by value 258 if a thread's execution is timed out

#include <windows.h>
#include <process.h>
#include <iostream>

//File: SimpleThreadExample.cpp

#define MAX_THREADS 3
using namespace std;

static unsigned __stdcall func(void *args)
{
    int tp = *(int *) args * 10;
    while(tp--)
    {
        cout << *(int *) args;
        ::Sleep(1000);
    }
    cout << endl;
    return 0;
}

int main()
{
    int param[MAX_THREADS] = { 1, 2, 3 };

    HANDLE handle[MAX_THREADS] = {0};
    unsigned tid[MAX_THREADS] = {0};

    // create threads
    for(int i = 0; i < MAX_THREADS; ++i)
    {
        handle[i] = (HANDLE)_beginthreadex(0, 0, &func, &param[i], CREATE_SUSPENDED, &tid[i]);
        cout << "Thread[" << tid[i] << "] Created" << endl;
    }

    // resume thread execution
    for(int i = 0; i < MAX_THREADS; ++i)
    {
        ::ResumeThread(handle[i]);
    }

    DWORD retval[MAX_THREADS];
    DWORD tslice[MAX_THREADS] = { 9 * 1000, 15 * 1000, 10 * 1000 };
    for(int i = 0; i < MAX_THREADS; ++i)
    {
        retval[i] = ::WaitForSingleObject(handle[i], tslice[i]);
    }

    DWORD ecode[MAX_THREADS];
    for(int i = 0; i < MAX_THREADS; ++i)
    {
        ::GetExitCodeThread(handle[i], &ecode[i]);
        ::CloseHandle(handle[i]);
    }

    cout << endl;
    for(int i = 0; i < MAX_THREADS; ++i)
    {
        cout << "Thread[" << tid[i] << "] terminated with retval=[" << retval[i] << "] & exitcode=[" << ecode[i] << "]" << endl;
    }

    return 0;
}

Output:

References:
http://www.codeproject.com/KB/threads/MultithreadingTutorial.aspx
http://msdn.microsoft.com/en-us/library/kdzttdcb%28v=vs.71%29.aspx

No comments :

Post a Comment