muduo源碼筆記-base-Mutex

1. MutexLock類

MutexLock類是對互斥量的封裝,使用棧上對象MutexLockGuard來管理mutex的加鎖與釋放。棧上對象在退出對應的代碼段之後會自動釋放,隨之,鎖也會被自動釋放。使用方法如下:

class Foo
{
public:
    int size() const;
private:
    mutable MutexLock mutex_;
    std::vector<int> data_ GUARDED_BY(mutex_);
};

int Foo::size() const
{
    MutexLockGuard lock(mutex_);
    return data_.size();
}

Mutex.h的部分源碼如下所示:

class CAPABILITY("mutex") MutexLock : noncopyable
{
 public:
  // 構造函數中初始化mutex變量   
  MutexLock()
    : holder_(0)
  {
    MCHECK(pthread_mutex_init(&mutex_, NULL));
  }
  // 析構函數中銷燬mutex變量
  ~MutexLock()
  {
    assert(holder_ == 0);
    MCHECK(pthread_mutex_destroy(&mutex_));
  }

  // 判斷加鎖的對象是否是當前線程
  bool isLockedByThisThread() const
  {
    return holder_ == CurrentThread::tid();
  }

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

  // 加鎖
  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_;           // 持有鎖的線程id
};

// 管理mutex加鎖與釋放的類(並不負責初始化與銷燬)
class SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
 public:
  // 構造對象時自動加鎖   
  explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
    : mutex_(mutex)
  {
    mutex_.lock();
  }
  // 釋放對象是釋放鎖
  ~MutexLockGuard() RELEASE()
  {
    mutex_.unlock();
  }

 private:

  MutexLock& mutex_;
};

2. Condition類

Condition類是對條件變量的封裝,使用到了MutexLock類

class Condition : noncopyable
{
 public:
  // 條件變量的初始化
  explicit Condition(MutexLock& mutex)
    : mutex_(mutex)
  {
    MCHECK(pthread_cond_init(&pcond_, NULL));
  }
  // 條件變量的銷燬
  ~Condition()
  {
    MCHECK(pthread_cond_destroy(&pcond_));
  }
  // 如果爲滿足條件,需要等待
  // 首先將鎖的持有者設置爲0
  // 然後對等待條件變量
  // 當等待結束時,會自動把鎖的持有者設置爲當前現場
  void wait()
  {
    MutexLock::UnassignGuard ug(mutex_);
    MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
  }

  // returns true if time out, false otherwise.
  bool waitForSeconds(double seconds);
  
  // 喚醒等待條件的某個線程
  void notify()
  {
    MCHECK(pthread_cond_signal(&pcond_));
  }
  // 喚醒等待條件的所有線程
  void notifyAll()
  {
    MCHECK(pthread_cond_broadcast(&pcond_));
  }

 private:
  MutexLock& mutex_;          // 互斥量
  pthread_cond_t pcond_;      // 條件變量
};

// 等待 seconds 秒
bool muduo::Condition::waitForSeconds(double seconds)
{
  struct timespec abstime;
  // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind.
  clock_gettime(CLOCK_REALTIME, &abstime);
  // 納秒級別轉換爲秒
  const int64_t kNanoSecondsPerSecond = 1000000000;
  int64_t nanoseconds = static_cast<int64_t>(seconds * kNanoSecondsPerSecond);

  abstime.tv_sec += static_cast<time_t>((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond);
  abstime.tv_nsec = static_cast<long>((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond);

  MutexLock::UnassignGuard ug(mutex_);
  // 超時返回true
  return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章