下面是摘自網絡的一段話,我覺得很好;對認識鎖很有幫助。 “為什麼要加鎖?加鎖是為了防止不同的線程通路同一共享資源造成混亂。
打個比方:人是不同的線程,衛生間是共享資源。
你在上洗手間的時候肯定要把門鎖上吧,這就是加鎖,隻要你在裡面,這個衛生間就被鎖了,隻有你出來之後别人才能用。想象一下如果衛生間的門沒有鎖會是什麼樣?
什麼是加鎖粒度呢?所謂加鎖粒度就是你要鎖住的範圍是多大。
比如你在家上衛生間,你隻要鎖住衛生間就可以了吧,不需要将整個家都鎖起來不讓家人進門吧,衛生間就是你的加鎖粒度。
怎樣才算合理的加鎖粒度呢?
其實衛生間并不隻是用來上廁所的,還可以洗澡,洗手。這裡就涉及到優化加鎖粒度的問題。
你在衛生間裡洗澡,其實别人也可以同時去裡面洗手,隻要做到隔離起來就可以,如果馬桶,浴缸,洗漱台都是隔開相對獨立的,實際上衛生間可以同時給三個人使用,當然三個人做的事兒不能一樣。這樣就細化了加鎖粒度,你在洗澡的時候隻要關上浴室的門,别人還是可以進去洗手的。如果當初設計衛生間的時候沒有将不同的功能區域劃分隔離開,就不能實作衛生間資源的最大化使用。這就是設計架構的重要性。” 從上述知道,有一種情況就是,當你進了衛生間,鎖上了門,這時你從窗戶逃走了,進而造成衛生間永遠被鎖住了。這就是其中一種死鎖。
是以可以設想的就是,當我們從衛生間出來的時候(無論正常出來,還是飛出來,...),都能把鎖打開,其它人就能進來。下面的代碼就能實作這個功能。
metux.h
#ifndef MUTEX_LOCK_H
#define MUTEX_LOCK_H
#ifndef WIN32
#include <windows.h>
#endif
#ifdef __unix
#include <pthread.h>
#endif // __unix
class Mutex
{
public:
Mutex();
~Mutex();
void Lock();
void Unlock();
private:
Mutex(const Mutex&);
void operator=(const Mutex&);
#ifdef WIN32
CRITICAL_SECTION m_mutex;
#endif // WIN32
#ifdef __unix
pthread_mutex_t m_mutex;
#endif // __unix
};
class MutexLock
{
public:
explicit MutexLock(Mutex *mutex) :m_mutex(mutex)
{
m_mutex->Lock();
};
~MutexLock()
{
m_mutex->Unlock();
};
private:
// 不允許複制
MutexLock(const MutexLock&);
void operator=(const MutexLock&);
Mutex *m_mutex;
};
#endif // !MUTEX_LOCK_H
mutex.cpp
#include "mutex.h"
Mutex::Mutex()
{
#ifdef WIN32
InitializeCriticalSection(&m_mutex);
#endif
#ifdef __unix
pthread_mutex_init(&m_mutex, NULL);
#endif // __unix
}
Mutex::~Mutex()
{
#ifdef WIN32
DeleteCriticalSection(&m_mutex);
#endif
#ifdef __unix
pthread_mutex_destroy(&m_mutex);
#endif // __unix
}
void Mutex::Lock()
{
#ifdef WIN32
EnterCriticalSection(&m_mutex);
#endif
#ifdef __unix
pthread_mutex_lock(&m_mutex);
#endif // __unix
}
void Mutex::Unlock()
{
#ifdef WIN32
LeaveCriticalSection(&m_mutex);
#endif
#ifdef __unix
pthread_mutex_unlock(&m_mutex);
#endif // __unix
}
測試
Mutex mutex;
void MutexTest()
{
MutexLock l(&mutex);
static int i = 0;
printf("i = %d\n", i);
++i;
}
原理就是,當MutexLock生命周期結束時,會調用析構函數,進而可以實作每次從衛生間出來都可以解鎖。當然你可以在MutexText添加大括号({})來限制MetexLock的生命同期,進而減小鎖的粒度。
這個設計無論是原理還是實作,還是蠻簡單的。前提是你有這方面的經驗,才會想到這種實作方法。
一年之後: 時間:20150611 最近想用C++ 11的裡面的std::mutex代替原來需要定義各種系統的mutex,因為這樣代碼更加簡潔。 上述設計是之前看LevelDB源碼學來,覺得挺好,于是分享出來。而今天修改代碼時候發現其實可以用宏定義。 例如:
#define MUTEX_LOCK()\
m_mutex.lock(); \
{
#define MUTEX_UNLOCK()\
}\
m_mutex.unlock();
如果,隻使用#define MUTEX_LOCK,沒有使用MUTEX_UNLOCK,編譯的時候肯定會報錯;很明顯,沒有MUTEX_UNLOCK,括号是不比對的。以前的方法是,如果你忘記了寫大括号來控制鎖的粒度,那麼很可能要到函數結束的時候才會解鎖。現在的方法不存在這種問題。 但是如果在MUTEX_LOCK 與 MUTEX_UNLOCK之間有return、goto等等,毫無疑問會出現死鎖。