-
-
Save yuri-tikhomirov/a81343dfd0eeaa4cc80a32aa095a2f5d to your computer and use it in GitHub Desktop.
Simple mutex wrapper class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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