Looking to do Multithreaded programming? In order to do that you're going to need a Mutex to prevent threads from accessing data at the same time! There are different techniques of preventing threads from accessing the same data, but they can't guarantee problems won't happen, it has to be implemented on the hardware side and exposed through the OS or what have you. Luckily, we can do this using some code from the Windows header files, using what's called Critical Section Objects, which works between threads on the same process, and is apparently a, "slightly faster, more efficient mechanism for mutual-exclusion synchronization." Sweeet!

Mutex_win32.h:

#ifndef w_Mutex_win32
#define w_Mutex_win32

#include <windows.h>

#include "../Definitions.h"

namespace _Warp
{
    class Mutex_win32
    {
    protected:
        CRITICAL_SECTION _critSection;

    public:
        Mutex_win32()
        {
            InitializeCriticalSection (&_critSection);
        }

        ~Mutex_win32()
        {
            DeleteCriticalSection (&_critSection);
        }

        void Lock()
        {
            EnterCriticalSection (&_critSection);
        }
        void Unlock()
        {
            LeaveCriticalSection (&_critSection);
        }

        Bool TryLock()
        {
            return (Bool)TryEnterCriticalSection(&_critSection);
        }
    };
}
#endif

Now, threading problems can be hard to track down and debug, especially if you forget to Unlock the Mutex. So a Lock object is a way to help you clean up and unlock the Mutex when you're done. A Lock is created on the Stack in a local block of code, so when the program leaves the block of code the Lock gets deleted, the destructor gets called, and in the process the Mutex is automatically unlocked in the Lock destructor.

Lock.h:

#ifndef w_Lock
#define w_Lock

#include "../Data/Uncopyable.h"

#include "Mutex_win32.h"

namespace _Warp
{
    class Lock
        : private Uncopyable
    {
    protected:
        Mutex_win32* _pMutex;

    public:
        explicit Lock(Mutex_win32* pMutex);
        ~Lock();
    };

    inline Lock::Lock(Mutex_win32* pMutex)
        : _pMutex( pMutex )
    {
        if(_pMutex != NULL)
        {
            _pMutex->Lock();
        }
    }

    inline Lock::~Lock()
    {
        if(_pMutex != NULL)
        {
            _pMutex->Unlock();
        }
    }
};
#endif

Here's an example of how to use a Lock and Mutex:

Mutex_win32* _pMessageListMutex = new Mutex_win32();//a mutex might typically exist in the header as a member variable
list<string> _messages = list<string>();// this 

void function()
{
    Lock lock = Lock(_pMessageListMutex);
    /* do stuff to the list */
}// when the program reaches here, the lock gets cleaned up and the _pMessageListMutex gets freed so another thread can access the _messages list without worrying about another thread accessing it at the same time

In case you didn't notice, the Lock class inherits from an "Uncopyable" class that doesn't allow the Lock to be copied or to be constructed from another Lock. This helps prevent errors from happening, besides the fact a lock shouldn't be copied anyway; so this class ensures it can't be. The Uncopyable class was inspired by the Boost Uncopyable class, though it wasn't the first site I ran across that showed something very similar.

Uncopyable.h:

#ifndef w_Uncopyable
#define w_Uncopyable

namespace _Warp
{
    // Inherit from this if you want a class to be unable to be copy-constructed.
    class Uncopyable
    {
    private:
        Uncopyable(const Uncopyable&);
        Uncopyable& operator=(const Uncopyable&);

    protected:
        Uncopyable(){}
        virtual ~Uncopyable(){}
    };
};
#endif

For those of you who don't know, the virtual destructor is required if any class inherits from Uncopyable, if you want it to properly be deleted. This should only be a problem if you store an object as an Uncopyable object, instead of it's own object type, and you try to delete it, the child's destructor will be properly called before the parent's destructor. Also, because the Copy constructor and copy operator aren't defined (besides the fact that they're private), you'll get a compiler error preventing you from doing anything you shouldn't be!

Both the Lock and Mutex class are pretty simple, so there isn't really much variation to them; I don't remember exactly which sites I used to lookup the Windows functions, otherwise I'd credit them for their help. Either way, if you had trouble finding C++ Mutex and Lock classes, I hope you find these useful for your purposes!

You can download the project files here: Mutex, Lock, and necessary class files.

Comments

There are no comments yet.

Next Post Previous Post