Skip to content

Instantly share code, notes, and snippets.

@yuri-tikhomirov
Forked from ytsutano/mutex.h
Last active May 27, 2016 16:51
Show Gist options
  • Save yuri-tikhomirov/a81343dfd0eeaa4cc80a32aa095a2f5d to your computer and use it in GitHub Desktop.
Save yuri-tikhomirov/a81343dfd0eeaa4cc80a32aa095a2f5d to your computer and use it in GitHub Desktop.
Simple mutex wrapper class
//
// From https://gist.github.com/ytsutano/4140432 by Yutaka Tsutano
// Modified by Yuri Tikhomirov
// (https://gist.github.com/yuri-tikhomirov/a81343dfd0eeaa4cc80a32aa095a2f5d)
//
// Refactored to support CRITICAL_SECTION usage on Windows,
// also made calls to lock() / try_lock() / unlock() inline.
//
// Performance tests:
// http://preshing.com/20111124/always-use-a-lightweight-mutex/
// win mutex: 608ns
// win critical section: 23.5ns
//
// So better to use critical section when you don't need
// cross-process synchronization.
//
// Also added Lock class and LOCK(mutex) macro. Usage:
// CrossMutex::Mutex m1;
// ...
// {
// LOCK(m1);
// // critical scope
// }
//
/**
* @file mutex.h
* @brief Declares Mutex class.
* @author Yutaka Tsutano
*/
#ifndef __CROSSMUTEX_DEFINED__
#define __CROSSMUTEX_DEFINED__
// include before namespace
#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#endif
namespace CrossMutex {
#ifdef _WIN32
// !!! Comment it out if you're working on a project !!!
// !!! that requires cross-process synchronization !!!
#define CROSSMUTEX_USE_CRIT_SECT
/**
* @brief Cross-platform mutex to protect the critical section.
*/
class Mutex {
private:
/**
* @brief Actual mutex used by the system.
*/
#ifndef CROSSMUTEX_USE_CRIT_SECT
HANDLE m;
#else
CRITICAL_SECTION crit_sect;
#endif
// disallow copying constructor
Mutex(const Mutex& that) {}
public:
/**
* @brief Constructor.
*/
Mutex() {
#ifndef CROSSMUTEX_USE_CRIT_SECT
m = CreateMutex(NULL, FALSE, NULL);
#else
::InitializeCriticalSection(&crit_sect);
#endif
}
/**
* @brief Desctructor.
*/
~Mutex() {
#ifndef CROSSMUTEX_USE_CRIT_SECT
CloseHandle(m);
#else
::DeleteCriticalSection(&crit_sect);
#endif
}
/**
* @brief Attempts to lock the mutex.
*/
inline bool try_lock() {
#ifndef CROSSMUTEX_USE_CRIT_SECT
return WaitForSingleObject(m, 0) == WAIT_OBJECT_0;
#else
return ::TryEnterCriticalSection(&crit_sect) ? true : false;
#endif
}
/**
* @brief Locks the mutex.
*/
inline void lock() {
#ifndef CROSSMUTEX_USE_CRIT_SECT
WaitForSingleObject(m, INFINITE);
#else
::EnterCriticalSection(&crit_sect);
#endif
}
/**
* @brief Unlocks the mutex.
*/
inline void unlock() {
#ifndef CROSSMUTEX_USE_CRIT_SECT
ReleaseMutex(m);
#else
::LeaveCriticalSection(&crit_sect);
#endif
}
};
#else
/**
* @brief Cross-platform mutex to protect the critical section.
*/
class Mutex {
private:
/**
* @brief Actual mutex used by the system.
*/
pthread_mutex_t m;
// disallow copying constructor
Mutex(const Mutex& that) {}
public:
/**
* @brief Constructor.
*/
Mutex() {
// let mutex support recursion
pthread_mutexattr_t mta;
pthread_mutexattr_init(&mta);
pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m, &mta);
}
/**
* @brief Desctructor.
*/
~Mutex() {
pthread_mutex_destroy(&m);
}
/**
* @brief Attempts to lock the mutex.
*/
bool try_lock() {
return pthread_mutex_trylock(&m) == 0;
}
/**
* @brief Locks the mutex.
*/
void lock() {
pthread_mutex_lock(&m);
}
/**
* @brief Unlocks the mutex.
*/
void unlock() {
pthread_mutex_unlock(&m);
}
};
#endif
class Lock
{
private:
Mutex& mutex;
public:
Lock(Mutex& m) : mutex(m) {
mutex.lock();
}
~Lock() {
mutex.unlock();
}
};
}
// crazy stuff from here: http://stackoverflow.com/a/1597129
// this allows to give unique names to variables of Lock class
#define __TOKENPASTE(x, y) x ## y
#define __TOKENPASTE2(x, y) __TOKENPASTE(x, y)
#define __LOCK __lock_
// prefer to use __COUNTER__ macro instead of __LINE__ when supported
// not sure #ifdef will work correct here o.O
#ifdef __COUNTER__
#define LOCK(mutex) CrossMutex::Lock __TOKENPASTE2(__LOCK,__COUNTER__)(mutex)
#else
#define LOCK(mutex) CrossMutex::Lock __TOKENPASTE2(__LOCK,__LINE__)(mutex)
#endif
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment