C++ 封装互斥对象

  多线程程序中为了防止线程并发造成的竞态,需要经常使用到Mutex进行数据保护。posix提供了phtread_mutex_t进行互斥保护数据。Mutex的使用需要初始化和释放对应(phtread_mutex_init() 和 phtread_mutex_destroy() 对应),上锁和解锁对应(phtread_mutex_lock 和 pthread_mutex_unlock对应)。lock和unlock的过程是设计逻辑的一部分一般都程序员都能正确的进行加锁和解锁对应,但是要防止lock之后程序出现异常或者提前return而没有unlock。初始化mutex之后不释放也会造成资源泄漏,也是很容易遗漏的地方。在实际开发中一般都需要自己封装一下Mutex。

class MutexLock 
{
 public:
  MutexLock() : holder_(0)
  {
    int ret = pthread_mutex_init(&mutex_, NULL);
    assert(ret == 0); 
  }

  ~MutexLock()
  {
    assert(holder_ == 0);
    int ret = pthread_mutex_destroy(&mutex_);
    assert(ret == 0); 
  }

  bool isLockedByThisThread() const
  {
    return holder_ == static_cast<pid_t>(::syscall(SYS_gettid));
  }

  void assertLocked() const
  {
    assert(isLockedByThisThread());
  }

  void lock()
  {
    pthread_mutex_lock(&mutex_);
    assignHolder();
  }

  void unlock()
  {
    unassignHolder();
    pthread_mutex_unlock(&mutex_);
  }

  pthread_mutex_t* getPthreadMutex()
  {
    return &mutex_;
  }

 private:
  
  MutexLock(const MutexLock &);
  MutexLock &operator=(const MutexLock &);

  void unassignHolder()
  {
    holder_ = 0;
  }

  void assignHolder()
  {
    holder_ = static_cast<pid_t>(::syscall(SYS_gettid));
  }

  pthread_mutex_t mutex_;
  pid_t holder_;
};


class MutexLockGuard 
{
 public:
  explicit MutexLockGuard(MutexLock& mutex)
    : mutex_(mutex)
  {
    mutex_.lock();
  }

  ~MutexLockGuard()
  {
    mutex_.unlock();
  }

 private:
  MutexLockGuard(const MutexLockGuard &);
  MutexLockGuard &operator=(const MutexLockGuard &);

  MutexLock& mutex_;
};

  为了提高MutextLock的易用性,增加了一个MutexLockGuard 类来封装MutextLock,实际使用的时候直接使用MutexLockGuard,这样就能防止忘记释放Mutex的情况出现(MutexLockGuard 超出作用域(一般是一个栈上变量)就会自动释放,调用析构函数,destroy掉mutex)。

  以上封装其实就是所谓的RAII的一个具体实践,C++中的智能指针shared_ptr,weak_ptr,unique_ptr 也是RAII的优秀实现。

  注:其实在C++11 线程库中已经有lock guard可以直接使用了(std::lock_guard ,只需要include<mutex>),不需要自己再写一遍,对于没有迁移到C++11上的项目可以使用自己封装的Mutex来提高易用性。

 

posted @ 2015-03-21 20:49  KingsLanding  阅读(1410)  评论(0编辑  收藏  举报