user152949
user152949

Reputation:

Correct way to implement simple thread safe generic mutex

I'm wondering if my way of implementing a generic mutex is a good software design pattern, and is it thread safe?

Here is my mutex class:

#ifdef HAVE_WINDOWS_H
void *CSimpleMutex::object;
#endif
#ifdef _PTHREADS
pthread_mutex_t CSimpleMutex::object;
#endif

CSimpleMutex::CSimpleMutex(bool lockable)
{
    isLockableMutex = lockable;
    if (!lockable)
    {
#ifdef _WINDOWS
        object = CreateMutex(NULL, false, NULL);
#endif
#ifdef _PTHREADS
        pthread_mutex_init(&object, NULL);
#endif
    }
    else
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&mutex);
#endif
#ifdef _PTHREADS
        pthread_mutex_init(&mutex, NULL);
#endif
    }
}

CSimpleMutex::~CSimpleMutex()
{
    if (!isLockableMutex)
    {
#ifdef _WINDOWS
        if(object!=NULL)
        {
            CloseHandle(object);
        }
#endif
#ifdef _PTHREADS
        pthread_mutex_destroy(&object);
#endif
    }
    else
    {
#ifdef _WINDOWS
        DeleteCriticalSection(&mutex);
#endif
#ifdef _PTHREADS
        pthread_mutex_destroy(&mutex);
#endif  
    }
}

// Aquires a lock
void CSimpleMutex::Lock()
{
    if (!isLockableMutex)
        return;
#ifdef _WINDOWS
    EnterCriticalSection(&mutex);
#endif
#ifdef _PTHREADS
    pthread_mutex_lock(&mutex);
#endif
}

// Releases a lock
void CSimpleMutex::Unlock()
{
    if (!isLockableMutex)
        return;
#ifdef _WINDOWS
    LeaveCriticalSection(&mutex);
#endif
#ifdef _PTHREADS
    pthread_mutex_unlock(&mutex);
#endif
}

This is how it is used:

class CEnvironment : public CHandleBase
{
    private:
        CSimpleMutex *mutex;
    public:
        CEnvironment(){mutex = new CSimpleMutex(true);};
        ~CEnvironment(){delete mutex;};
        void Lock() { mutex->Lock(); };
        void Unlock() { mutex->Unlock(); };
        void DoStuff(void *data);
};

When I want to use CEnvironment I do something like this:

env->Lock();
env->DoStuff(inData);
env->Unlock();

Upvotes: 0

Views: 1813

Answers (1)

Void - Othman
Void - Othman

Reputation: 3481

You'd typically use RAII to acquire and release a lock on entering and leaving a given scope, respectively, so that the lock is automatically released if an exception is thrown within that scope. In your case, you could define an addition lock "guard" class that acquires the lock in its constructor and releases in its destructor. The C++11 standard, for example, defines several mutex classes and a std::lock_guard class that provide the behavior I just described.

The paper "Strategized Locking, Thread-safe Interface, and Scoped Locking" by Doug Schmidt provides additional design details and ideas that may be of use.

Upvotes: 1

Related Questions