Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C++
Article

Using WIN32 Message Queue in C++ / WIN32 Multithreaded Applications

Rate me:
Please Sign up or sign in to vote.
4.42/5 (45 votes)
24 Feb 2004CPOL3 min read 218.2K   2.2K   89   32
How to use WIN32 Message Queues in MultiThreaded Environments instead of kernel objects.

Introduction and Motivations

I am not a great lover of Multithreaded applications development, but at the end I come up with writing more multithreaded applications than single threaded ones. Though they are little bit difficult to manage, sometimes they provide us unique opportunity to solve a particular problem, provided your application is not CPU intensive. if your application is CPU intensive then multithreading will not give you its stated performance.

Every application is having its own thread creation policies for example

  • Application may create a thread pool and waits for the requests to be serviced.
  • Application may create thread on the fly when it needs to service some request.

In case 1 you need to have some mechanism to make a thread wait for some kind of signal. The signal may be generated in case when you need the service of any particular thread.

Using WIN32 Kernel Objects

WIN32 provides kernel objects like WIN32 Events to handle this kind of situations. you can use one of the WaitFor.. APIs to wait for a particular event inside a thread. The idea behind waiting for kernel objects is that it won't eats up all of the available CPU while waiting, otherwise you could have busy wait. Look at the following code.

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

using namespace std;

HANDLE        hEvent;

DWORD    WINAPI ThrdFunc ( LPVOID n )
{
    int        TNumber    =    (int) n;
    WaitForSingleObject ( hEvent , INFINITE );
    cout<<"Event gets signaled...."<<endl;
    return 0;
}

int    main()
{
    HANDLE        hThrd;
    DWORD        Id;
    //    Create a Event
    hEvent    =    CreateEvent ( NULL , false , false , "Event 10234" );

    hThrd    =    CreateThread ( NULL , 0 , 
       (LPTHREAD_START_ROUTINE)ThrdFunc ,
       (LPVOID)0 , 0 , &Id );
    if ( !hThrd )
    {
        cout<<"Error Creating Thread ..."<<endl;
        return -1;
    }
    //    Wait For some time before giving out any signal
    Sleep ( 2000 );
    SetEvent ( hEvent );
    //    Wait for the thread to gets killed
    WaitForSingleObject ( hThrd , INFINITE );
    //    Close the handler
    CloseHandle ( hEvent );
    CloseHandle ( hThrd );
    return 0;
}

The code above shows that a thread is being created and it is waiting for an auto reset event. The event is signaled by the main thread after 2 seconds. once the waiting thread gets the signal it continues its execution and exit. You can achieve the same functionality using WIN32 Message queues.

Using WIN32 Message Queues

WIN32 message queues have certain advantages as compared to event based mechanism. As we will see you can send different messages to a single thread. The following code uses PostThreadMessage WIN32 API to post specific message to a particular thread.

Advantage Message Queue over Events

  • You are sure that you are posting message to which thread, while in the case of events you can't guarantee which thread will get released if more than one threads are waiting on same event.
  • You can send a range of user defined messages to a thread, if you want the thread to behave differently. However in case of events you can just signal the events, no other information can be given.

Using Message queue in Multithreaded application

Message queues can be created even in console applications. you don't need a windows handle for it. Message queues are created in WIN32 console application as soon as you call message extractor functions like GetMessage and PeekMessage.

In my code below I have used GetMessage. PeekMessage is commented. The only harm in using PeekMessage is that PeekMessage doesn't waits for the message to come into the queue and will eats up all the available CPU which is undesirable in many cases. Here is the code

//    User Defines Messages
#define        THRD_MESSAGE_SOMEWORK        WM_USER + 1
#define        THRD_MESSAGE_EXIT            WM_USER + 2
//    Application Specific Preprocessor definitions
#define        NUM_THREADS                    2

DWORD WINAPI    ThrdFunc ( LPVOID n )
{
    int    TNumber    =    ( int )n;
    //    Here we will wait for the messages
    while ( 1 )
    {
        MSG    msg;
        //BOOL    MsgReturn  =  PeekMessage ( &msg , NULL , 
        //    THRD_MESSAGE_SOMEWORK , THRD_MESSAGE_EXIT , PM_REMOVE );
        BOOL    MsgReturn    =    GetMessage ( &msg , NULL , 
            THRD_MESSAGE_SOMEWORK , THRD_MESSAGE_EXIT );
            
        if ( MsgReturn )
        {
            switch ( msg.message )
            {
            case THRD_MESSAGE_SOMEWORK:
                cout<<"Working Message.... for Thread Number "
                   <<TNumber<<endl;
                break;
            case THRD_MESSAGE_EXIT:
                cout<<"Exiting Message... for Thread Number "
                   <<TNumber<<endl;
                return 0;
            }
        }
    }
    
    return 0;
}

int main()
{
    HANDLE    hThrd [ NUM_THREADS ];
    DWORD    Id [ NUM_THREADS ];
    short LoopCounter = 0;
    //    Create all the threads
    for ( ; LoopCounter < NUM_THREADS ; LoopCounter ++ )
    {
        hThrd [ LoopCounter ] = CreateThread ( NULL , 0 , 
            (LPTHREAD_START_ROUTINE)ThrdFunc , 
            (LPVOID)LoopCounter , 0, &Id [ LoopCounter ] );
        if ( !hThrd )
        {
            cout<<"Error Creating Threads,,,,.exiting"<<endl;
            return -1;
        }
        Sleep ( 100 );
    }
    Sleep ( 10000 );
    //    Send Working Message to all Threads 
    for ( LoopCounter = 0; LoopCounter < NUM_THREADS ; LoopCounter ++ )
    {
        PostThreadMessage ( Id [ LoopCounter ] , 
            THRD_MESSAGE_SOMEWORK , 0 , 0 );
        Sleep ( 100 );
    }
    //    Sleep againg for 1 seconds and send exit message to all threads
    Sleep ( 1000 );
    for ( LoopCounter = 0; LoopCounter < NUM_THREADS ; LoopCounter ++ )
    {
        PostThreadMessage ( Id [ LoopCounter ] , THRD_MESSAGE_EXIT, 0 , 0 );
        Sleep ( 100 );
    }
    //    Wait for all threads to exit
    WaitForMultipleObjects ( NUM_THREADS, hThrd , true , INFINITE );
    //    Close All handles
    for ( LoopCounter = 0; LoopCounter < NUM_THREADS ; LoopCounter ++ )
        CloseHandler ( hThrd [ LoopCounter ] );

    return 0;
}

In the code above we created two user defined messages. Each thread waits for the particular message. The message is send to all threads from the main thread. The main thread waits for all threads to exit before exiting itself.

History

  • Last updated on Feb 26, 2004

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India
A programmer by heart since 1998. Written code in C++, Java, JavaScript, Python & Ruby, Worked on Stack Development to Web Development. Data Specialist with SQL and NoSQL DBs

Comments and Discussions

 
GeneralMy vote of 2 Pin
ranjithkumar8120-Dec-12 19:47
ranjithkumar8120-Dec-12 19:47 
GeneralRe: My vote of 2 Pin
itsdkg18-Jun-13 18:34
itsdkg18-Jun-13 18:34 
GeneralMy vote of 5 Pin
ranjithkumar8120-Dec-12 19:41
ranjithkumar8120-Dec-12 19:41 
QuestionThanks Pin
pkv99024-Mar-12 17:33
pkv99024-Mar-12 17:33 
GeneralNice Aritical Pin
gauravagarwal.cs@gmail.com13-Sep-07 2:14
gauravagarwal.cs@gmail.com13-Sep-07 2:14 
GeneralVery nice Aritical Pin
muthulakshmanan7-Dec-06 19:17
muthulakshmanan7-Dec-06 19:17 
GeneralMulti-threaded DLL Pin
JRaiden30-Jan-06 1:27
JRaiden30-Jan-06 1:27 
GeneralMessage Queue Size Pin
Ravi Ranjan18-Jul-05 18:29
Ravi Ranjan18-Jul-05 18:29 
GeneralRe: Message Queue Size Pin
Ason19-Jan-09 19:58
Ason19-Jan-09 19:58 
GeneralUser defined Message handling Pin
dharani6-Sep-04 3:00
dharani6-Sep-04 3:00 
QuestionWhen the thread created its mesage queue ? Pin
Tom_lyd1-Mar-04 19:30
Tom_lyd1-Mar-04 19:30 
AnswerRe: When the thread created its mesage queue ? Pin
Prakash Nadar1-Mar-04 19:46
Prakash Nadar1-Mar-04 19:46 
GeneralRe: When the thread created its mesage queue ? Pin
.:floyd:.3-Mar-04 8:05
.:floyd:.3-Mar-04 8:05 
GeneralRe: When the thread created its mesage queue ? Pin
Prakash Nadar3-Mar-04 13:13
Prakash Nadar3-Mar-04 13:13 
GeneralRe: When the thread created its mesage queue ? Pin
.:floyd:.4-Mar-04 3:15
.:floyd:.4-Mar-04 3:15 
GeneralRe: When the thread created its mesage queue ? Pin
Dandy Cheung4-Mar-04 23:18
Dandy Cheung4-Mar-04 23:18 
GeneralRe: When the thread created its mesage queue ? Pin
winsute23-Mar-05 18:48
winsute23-Mar-05 18:48 
GeneralRe: When the thread created its mesage queue ? Pin
Dandy Cheung23-Mar-05 19:21
Dandy Cheung23-Mar-05 19:21 
GeneralRe: When the thread created its mesage queue ? Pin
winsute23-Mar-05 19:53
winsute23-Mar-05 19:53 
GeneralMore solid thread synchronization Pin
.:floyd:.25-Feb-04 6:36
.:floyd:.25-Feb-04 6:36 
GeneralRe: More solid thread synchronization Pin
Prakash Nadar3-Mar-04 13:20
Prakash Nadar3-Mar-04 13:20 
Its a good idea but i dont know wheather there is a "flaw"

To you use messagequeue for syncronization according to me is a bad idea.
When thread is created, message queue is not created it is created when a message is read from the queue, fine but dont ya think now its consuming more memory.???

Instead a simple event will do the same with less memory consumption.
I feel that if the thread is a worker thread then this idea is not acceptable.

But its a very good idea for ui thread.
GeneralRe: More solid thread synchronization Pin
.:floyd:.4-Mar-04 3:59
.:floyd:.4-Mar-04 3:59 
GeneralReasons for Sleep(100) Pin
DeckerDK24-Feb-04 21:50
DeckerDK24-Feb-04 21:50 
GeneralPerformance Pin
Marc Wohlers20-Feb-04 1:46
Marc Wohlers20-Feb-04 1:46 
GeneralRe: Performance Pin
itsdkg20-Feb-04 17:27
itsdkg20-Feb-04 17:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.