Monday 11 May 2009

Another Multi-Threading example with Mutex

Here is an example where we combine the previous programs to create a multi-threaded mutex based program. If you havent already seen, then please check out the Singleton class and Multi-Threading with Thread Sync.

We are going to have some .h files in this example.

Lock.h

//Example from http://www.relisoft.com/Win32/active.html
#if !defined _LOCK_H_
#define _LOCK_H_

#include "Mutex.h"

class
Lock
{

public
:
// Acquire the state of the semaphore
Lock ( Mutex & mutex )
:
_mutex(mutex)
{

_mutex.Acquire();
}

// Release the state of the semaphore
~Lock ()
{

_mutex.Release();
}

private
:
Mutex & _mutex;
};


#endif



Mutex.h

//Example from http://www.relisoft.com/Win32/active.html
#if !defined _MUTEX_H_
#define _MUTEX_H_

class
Mutex
{

friend class
Lock;
public
:
Mutex () { InitializeCriticalSection (& _critSection); }
~
Mutex () { DeleteCriticalSection (& _critSection); }
private
:
void
Acquire ()
{

EnterCriticalSection (& _critSection);
}

void
Release ()
{

LeaveCriticalSection (& _critSection);
}


CRITICAL_SECTION _critSection;
};


#endif



Singleton.h

#include "Lock.h"
#include "Mutex.h"

class
aSingletonClass
{

public
:
//method to get Instance of class
static aSingletonClass *getInstance( void )
{

//Note that the class is only created when this method is called first time
if(!instance_)
instance_ = new aSingletonClass;
return
instance_;
}

//method to delete Instance of class
static void deleteInstance( void )
{

if
(instance_)
delete
instance_;
instance_ = NULL; //important as this can create dead reference problems
}
void
printSomething(char *name, int count)
{

Lock guard(mutex_);
std::cout << name << " loop " << count << std::endl;
}


private
:
//variable to store the instance of singleton
static aSingletonClass *instance_;
//default constructor should be private to prevent instantiation
aSingletonClass() {};
//destructor should be made private so no one can delete this accidently
~aSingletonClass() {};
//We also need to prevent copy being created of the object
aSingletonClass(const aSingletonClass&);

Mutex mutex_;
};



Thread.cpp

//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//This shows example of Multithreading, thread sync, Mutex
#include <windows.h>
#include <process.h>
#include <iostream>
#include "Singleton.h"

using namespace
std;

aSingletonClass* aSingletonClass::instance_ = NULL;

void
Func1(void *);
void
Func2(void *);

int
main()
{

HANDLE hThreads[2];

aSingletonClass *someVar = NULL;
//Create Instance
someVar = aSingletonClass::getInstance();

//Create two threads and start them
hThreads[0] = (HANDLE)_beginthread(Func1, 0, NULL);
hThreads[1] = (HANDLE)_beginthread(Func2, 0, NULL);

//Makes sure that both the threads have finished before going further
WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);

cout << "Main exit" << endl;
return
0;
}


void
Func1(void *P)
{

int
Count;

for
(Count = 1; Count < 11; Count++)
{

aSingletonClass::getInstance()->printSomething("Func1", Count);
}

return
;
}


void
Func2(void *P)
{

int
Count;

for
(Count = 10; Count > 0; Count--)
{

aSingletonClass::getInstance()->printSomething("Func2", Count);
}

return
;
}





The Output is as follows:

17 comments:

  1. it doesn't synchronized in my computer (windows 7 with Intel core 2)

    ReplyDelete
  2. Please copy and paste your output in comments and then we can see what you are getting.

    ReplyDelete
  3. I got the same problem, my output is this:

    [code]
    Func1 loop 1
    Func1 loop 2
    Func1 loop 3
    Func1 loop 4
    Func1 loop 5
    Func1 loop 6
    Func1 loop 7
    Func1 loop 8
    Func1 loop 9
    Func1 loop 10
    Func2 loop 10
    Func2 loop 9
    Func2 loop 8
    Func2 loop 7
    Func2 loop 6
    Func2 loop 5
    Func2 loop 4
    Func2 loop 3
    Func2 loop 2
    Func2 loop 1
    Main exit
    [/code]

    Compiled with VS2008, Vista 64 bit, Intel Quad Q9660

    ReplyDelete
  4. the same, doesnot work.

    ReplyDelete
  5. u need 1) change to
    void Acquire ()
    {
    while(mutexAcquired){Sleep(1);};
    EnterCriticalSection (& _critSection);
    mutexAcquired = true;
    }
    void Release ()
    {
    LeaveCriticalSection (& _critSection);
    mutexAcquired = false;
    }

    2) put Sleep(1) f.e. after
    aSingletonClass::getInstance()->printSomething(...
    Without delay first thread completing processing before second one starts)

    ReplyDelete
  6. Strange I didnt see this problem of multiple PC's.

    ReplyDelete
  7. What value would you assign mutexAcquired initially? and where would you declare it?
    Thanks!

    ReplyDelete
  8. I guess this comment is based on the earlier comment. mutexAcquired should be set to false in Mutex constructor.

    ReplyDelete
  9. Any Answers/suggestions for this Question?

    If one uses a friend function in the singleton class declaration, then its possible to create multiple instances???

    ReplyDelete
  10. Bharath, yes you can create multiple instances but what is the point of using Singleton?

    ReplyDelete
  11. do we also have asynchronous multithreading in C++ ? how to code synchronous and asynsynchronous multi threading in c++?

    ReplyDelete
  12. Raksha, if you remove Lock guard(mutex_); it will become asynchronous. By default the threads are asynchronous but you can use approaches like Mutex to make it synchronous.

    ReplyDelete
  13. Hi Zahid,

    Should there be a mutex protecting
    LOCK()
    if(!instance_)
    instance_ = new aSingletonClass; so that
    UNLOCK()

    So that it is executed atomically? I feel if this is not done multiple threads may perform this 'new' command simultaneously creating multiple instances which may create a memory leak.

    Your Thoughts

    Cheers,

    ReplyDelete
  14. Hi Michael, yes you can do that. Singleton's should be created in the main function and should be created before any threads are created. I am sure not everyone strictly follows this so a Mutex would certainly help.

    ReplyDelete
  15. Hey Zahid,

    I see - you create the instance before everything starts multitasking so there is no contention. Great idea - thanks for the help and fast response :)

    Cheers,

    Michael

    ReplyDelete
  16. Zahid, thanks for this interesting blog. But I tested it in my computer(win7+core8+vs2008) and got the different result from yours, which was also pointed out by two anonymous readers. Could you tell me what configuration I did wrong ? thanks.

    Func1 loop 1
    Func1 loop 2
    Func1 loop 3
    Func1 loop 4
    Func1 loop 5
    Func1 loop 6
    Func1 loop 7
    Func1 loop 8
    Func1 loop 9
    Func1 loop 10
    Func2 loop 10
    Func2 loop 9
    Func2 loop 8
    Func2 loop 7
    Func2 loop 6
    Func2 loop 5
    Func2 loop 4
    Func2 loop 3
    Func2 loop 2
    Func2 loop 1
    Main exit

    ReplyDelete
  17. See comment of Oct 22, 2010 09:06 AM.

    ReplyDelete