MutexLock

class CAPABILITY("mutex") MutexLock : noncopyable
{
 public:
  MutexLock()
    : holder_(0)
  {
    MCHECK(pthread_mutex_init(&mutex_, NULL));
  }

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

  // must be called when locked, i.e. for assertion
  bool isLockedByThisThread() const
  {
    return holder_ == CurrentThread::tid();
  }

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

  // internal usage

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

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

  pthread_mutex_t* getPthreadMutex() /* non-const */
  {
    return &mutex_;
  }

 private:
  friend class Condition;

  class UnassignGuard : noncopyable
  {
   public:
    explicit UnassignGuard(MutexLock& owner)
      : owner_(owner)
    {
      owner_.unassignHolder();
    }

    ~UnassignGuard()
    {
      owner_.assignHolder();
    }

   private:
    MutexLock& owner_;
  };

  void unassignHolder()
  {
    holder_ = 0;
  }

  void assignHolder()
  {
    holder_ = CurrentThread::tid();
  }

  pthread_mutex_t mutex_;
  pid_t holder_;
};

// Use as a stack variable, eg.
// int Foo::size() const
// {
//   MutexLockGuard lock(mutex_);
//   return data_.size();
// }
class SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
 public:
  explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
    : mutex_(mutex)
  {
    mutex_.lock();
  }

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

 private:

  MutexLock& mutex_;
};

Mutex.h头文件实现了一个采用RAII管理的锁。

其中MutexLock类就是实现了一个锁的基本操作,包含两个成员,mutex_就是内部锁,holder_记录拥有锁的线程,采用构造函数初始化锁,析构函数销毁锁,并提供了判断锁是否为本线程所持有的isLockedByThisThread接口,以及lock和unlock操作。getPthreadMutex是条件变量使用的接口,因为条件变量需要锁的指针。该类中最不容易理解的是私有类UnassignGuard的作用。先说MutexLockGuard,最后再说UnassignGuard。MutexLockGuard很简单,就是通过构造和析构来调用加解锁,将RAII原则贯彻到底,避免忘记释放锁。

最后说UnassignGuard,只有一个成员,即MutexLock的引用。该类只有构造函数和析构函数,其中构造函数将holder_赋值为0,析构函数将holder_赋值为当前线程,其实这个内部类,也是提供条件变量使用的,之后还会单独写一个关于条件变量的,但是这里先说一下。

在ThreadPool.cc中有这么一段代码,

    MutexLockGuard lock(mutex_);
    while (isFull() && running_)
    {
      notFull_.wait();
    }

这时候MutexLockGuard会调用MutexLock的lock接口,lock接口会调用assignHolder将holder_赋值为当前线程,而notFull条件变量在调用wait接口代码如下:

  void wait()
  {
    MutexLock::UnassignGuard ug(mutex_);
    MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
  }

可以看到wait里会先调用UnassignGuard的构造函数,之后pthread_cond_wait会释放mutex_,由于MutexLockGuard没有析构,所以无法通过MutexLockGuard析构函数调用unlock释放锁,在调用unlock时会将holder_赋值为0,所以UnassignGuard的构造函数相当于替代MutexLockGuard析构函数。再说UnassignGuard的析构函数,在pthread_cond_wait后释放了mutex_后,被其他线程获取该锁,之后释放,最终notFull条件变量被唤醒的时候,会自动加锁,可是这时候锁的holder_已经被其他线程修改了,所以这时候阻塞在notFull的线程获取的锁需要修改holder_为自己的线程ID,否则调用isLockedByThisThread就会失败,这个修改holder_的功能就是通过UnassignGuard的析构实现的。

上面大体上就是我现在的理解,可能有不对的地方,之后再修改吧。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值