MutexLock 封装临界区(critical section),这是一个简单的资源类,用RAII 手法[CCS,条款13] 封装互斥器的创建与销毁。临界区在Windows 上是struct CRITICAL_SECTION,是可重入的;在Linux 下是pthread_mutex_t,默认是不可重入的。MutexLock 一般是别的class 的数据成员。
MutexLockGuard 封装临界区的进入和退出,即加锁和解锁。MutexLockGuard 一般是个栈上对象,它的作用域刚好等于临界区域。
class noncopyable
{
public:
noncopyable(const noncopyable&) = delete; //禁止生成
void operator=(const noncopyable&) = delete;
protected:
noncopyable() = default;
~noncopyable() = default;
};
class MutexLock : noncopyable
{
public:
MutexLock()
{
pthread_mutex_init(&mutex_, NULL); //初始化互斥量
}
~MutexLock()
{
pthread_mutex_destroy(&mutex_); //销毁互斥量
}
// internal usage
void lock()
{
pthread_mutex_lock(&mutex_);
}
void unlock()
{
pthread_mutex_unlock(&mutex_);
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
pthread_mutex_t mutex_;
};
class MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex)
: mutex_(mutex)
{
mutex_.lock(); //调用互斥量上锁
}
~MutexLockGuard()
{
mutex_.unlock(); //调用互斥量解锁
}
private:
MutexLock& mutex_;
};
class Condition : noncopyable
{
public:
explicit Condition(MutexLock& mutex)
: mutex_(mutex)
{
pthread_cond_init(&pcond_, NULL);
}
~Condition()
{
pthread_cond_destroy(&pcond_);
}
void wait()
{
MutexLock::UnassignGuard ug(mutex_);
pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
}
// returns true if time out, false otherwise.
bool waitForSeconds(double seconds);
void notify()
{
pthread_cond_signal(&pcond_);
}
void notifyAll()
{
pthread_cond_broadcast(&pcond_);
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
实例:
编写单个的线程安全的 class 不算太难,只需用同步原语保护其内部状态。例如 下面这个简单的计数器类 Counter:
// A thread-safe counter
class Counter : boost::noncopyable
{
// copy-ctor and assignment should be private by default for a class.
public:
Counter() : value_(0) {}
int64_t value() const;
int64_t getAndIncrease();
private:
int64_t value_;
mutable MutexLock mutex_;
};
int64_t Counter::value() const
{
MutexLockGuard lock(mutex_); // lock 的析构会晚于返回对象的构造,
return value_; // 因此有效地保护了这个共享数据。
}
int64_t Counter::getAndIncrease()
{
MutexLockGuard lock(mutex_); //返回对象前,lock的析构函数会自动调用释放互斥锁函数
int64_t ret = value_++;
return ret;
}
//
总结:由上代码分析知,MutexLockGuard类解决了自动释放互斥量的问题,可有效避免人为失误的问题。