Linux多線程編程工具庫liblmp_tool github: https://github.com/Dwyane05/liblmp_tool
互斥鎖(mutex)恐怕是使用得最多的同步原語,粗略地說,它保護了臨界區,任何一個時刻最多只能有一個線程在此mutex劃出的臨界區內活動。單獨使用mutex時,我們主要爲了保護共享數據。
個人的原則是:
·用RAII手法封裝mutex的創建、銷燬、加鎖、解鎖這四個操作。用RAII封裝這幾個操作是通行的做法,這幾乎是C++的標準實踐。
·只用非遞歸的mutex(即不可重入的mutex)。
·不手工調用lock()和unlock()函數,一切交給棧上的Guard對象的構造和析構函數負責。Guard對象的生命期正好等於臨界區(分析對象在什麼時候析構是C++程序員的基本功)。
·在每次構造Guard對象的時候,思考一路上(調用棧上)已經持有的鎖,防止因加鎖順序不同而導致死鎖(deadlock)。
次要原則有:
·不使用跨進程的mutex,進程間通信只用TCP sockets。
·加鎖、解鎖在同一個線程,線程a不能去unlock線程b已經鎖住的mutex(RAII自動保證)。
·別忘了解鎖(RAII自動保證)。
·不重複解鎖(RAII自動保證)。
·必要的時候可以考慮用PTHREAD_MUTEX_ERRORCHECK來排錯。
相關類的實現:
#include "Thread.h"
#include “noncopyable.h”
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
namespace lmp_tool
{
class MutexLock : noncopyable
{
public:
MutexLock()
: holder_(0)
{
pthread_mutex_init(&mutex_, NULL);
}
~MutexLock()
{
assert(holder_ == 0);
pthread_mutex_destroy(&mutex_);
}
bool isLockedByThisThread()
{
return holder_ == CurrentThread::tid();
}
void assertLocked()
{
assert(isLockedByThisThread());
}
// internal usage
void lock()
{
pthread_mutex_lock(&mutex_);
holder_ = CurrentThread::tid();
}
void unlock()
{
holder_ = 0;
pthread_mutex_unlock(&mutex_);
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
private:
pthread_mutex_t mutex_;
pid_t holder_;
};
class MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex)
{
mutex_.lock();
printf( "mutex locked\n");
}
~MutexLockGuard()
{
mutex_.unlock();
printf( "mutex unlocked\n");
}
private:
MutexLock& mutex_;
};
}
// Prevent misuse like:
// MutexLockGuard(mutex_);
// A tempory object doesn't hold the lock for long!
#define MutexLockGuard(x) error "Missing guard object name"