Encapsulation critical region and conditional variable

Three tool classes in critical region

Mutex lock encapsulates the critical area, and RAII encapsulates the creation and destruction of mutex. MutexLock is usually a data member of another class
Mutex lockguard encapsulates the entry and exit of critical area, that is, mutex locking and unlocking. MutexLockGuard is usually a stack variable with a scope just equal to the critical area.
Condition encapsulates wait and notify operations

Uncopyable package

class Uncopyable
{
public:
protected:
	Uncopyable(){};    //Allow derived class objects to be constructed and destructed
	~Uncopyable(){};
private:
	Uncopyable(const Uncopyable&);    //Prevent copying
	Uncopyable& operator=(const Uncopyable&);
};

MutexLock package

class MutexLock : Uncopyable
{
 public:
  MutexLock()
    : holder_(0)
  {
    pthread_mutex_init(&mutex_, NULL);
  }

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

  bool isLockedByThisThread()
  {
    return holder_ == gettid();    //Determine whether the current thread has taken the lock
  }

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

  // lock and unlock are generally called for MutexLockGuard
  void lock()
  {
    pthread_mutex_lock(&mutex_);
    holder_ = gettid();
  }

  void unlock()
  {
    holder_ = 0;
    pthread_mutex_unlock(&mutex_);
  }

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

 private:

  pthread_mutex_t mutex_;
  pid_t holder_;
};

MutexLockGuard package

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

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

 private:
  MutexLock& mutex_;
};

Condition encapsulation

There are two ways of waiting conditions: conditional waiting for pthread ﹣ cond ﹣ wait() and timing waiting for pthread ﹣ cond ﹣ timedwait(), where the timing waiting method returns ETIMEDOUT if the conditions are not met before the given timing, ending the waiting, where absolute appears in the same absolute time form as the time() system call, 0 means 0:00:00 GMT on January 1, 1970.

class Condition : boost::Uncopyable
{
 public:
  explicit Condition(MutexLock& mutex) : mutex_(mutex)
  {
    pthread_cond_init(&pcond_, NULL);
  }

  ~Condition()
  {
    pthread_cond_destroy(&pcond_);
  }

  void wait()
  {
    pthread_cond_wait(&pcond_, mutex_.getPthreadMutex());
  }

  // Return TRUE if timeout, FALSE otherwise
  bool waitForSeconds(int seconds)
  {
    struct timespec abstime;
    clock_gettime(CLOCK_REALTIME, &abstime);
    abstime.tv_sec += seconds;
    return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime);
  }

  void notify()
  {
    pthread_cond_signal(&pcond_);
  }

  //May cause shock phenomenon
  void notifyAll()
  {
    pthread_cond_broadcast(&pcond_);
  }

 private:
  MutexLock& mutex_;
  pthread_cond_t pcond_;
};

Posted on Sun, 01 Dec 2019 17:01:11 -0800 by Vince889