mudu庫學習篇-mutex類封裝學習

muduo庫是高併發的linux網絡編程庫,那麼就一定有mutex對mutex類的封裝,在多線程的編程中,線程間經常會操作一些全局變量,因此我們就需要一些同步的機制,我的上一篇博客condtion算是一種,當然了conditon一般都是和mutex來結合使用。接下來我們看看muduo庫對mutex的封裝

mutex.h
namespace muduo
{

// Use as data member of a class, eg.
//
// class Foo
// {
//  public:
//   int size() const;
//
//  private:
//   mutable MutexLock mutex_;
//   std::vector<int> data_ GUARDED_BY(mutex_);
// };
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_;
};

}  // namespace muduo

// Prevent misuse like:
// MutexLockGuard(mutex_);
// A tempory object doesn't hold the lock for long!
#define MutexLockGuard(x) error "Missing guard object name"

#endif  // MUDUO_BASE_MUTEX_H

mutex.h中有對mutex的封裝的Mutexlock類,還有基於Mutexlock封裝的MutexLockGuard
  • Mutexlock類

    在mutexlock類中有兩個成員變量:

    pthread_mutex_t mutex_ linux互斥鎖
    pid_t holder_; 進程id類型

    mutexlock的構造函數實現對mutex的初始化,和進程id的初始化,默認值爲0

  • MutexLockGuard類

    MutexLockGuard類的實現思想有些類似智能指針,通過使用MutexLockGuard,在多線程編程的時候可以防止開發者忘記對鎖的釋放

    實現的思想就是,將對互斥鎖的控制交給操作系統,通過一個棧區變量管理一個全局變量,當棧區變量從作用域結束時,系統自動調用該棧區的析構函數從而達到釋放鎖的目的,智能指針就是把一個指針的釋放問題從程序員轉移給系統,只不過是只能指針有

    關鍵的地方是,MutexLockGuard類中的成員變量必須是一個&類型的變量,其次在構造函數調用mutexlock的lock函數,析構函數調用mutexlock的unlock函數。

拓展

c++11中mutex,c++11中也對mutex進行封裝,使用方式和muduo庫差不多,同時c++11中也有類似MutexLockGuard的實現,下面我來介紹一下c++11中基於mutex封裝的lock_guard和unique_lock;

lock_guard

#include <thread>
#include <mutex>
#include <vector>
#include <iostream>
#include <algorithm>

std::mutex my_lock;

void add(int &num, int &sum){
    while(true){
        std::lock_guard<std::mutex> lock(my_lock);  
        if (num < 100){ //運行條件
            num += 1;
            sum += num;
        }   
        else {  //退出條件
            break;
        }
        //sleep(100);
    }   
}

int main(){
    int sum = 0;
    int num = 0;
    std::vector<std::thread> ver;   //保存線程的vector
    for(int i = 0; i < 20; ++i){
        std::thread t = std::thread(add, std::ref(num), std::ref(sum));
        ver.emplace_back(std::move(t)); //保存線程
    }   

    std::for_each(ver.begin(), ver.end(), 			      std::mem_fn(&std::thread::join)); //join
    std::cout << sum << std::endl;
}

同樣上面的代碼使用muduo庫中MutexLockGuard是一樣的。muduo庫的MutexLockGuard和c++11的lock_guard有一個問題,假如我在線程中操作完全局變量後,還有很長的處理邏輯,可能要花很長時間才能結束,例如我在上面sleep(100),這樣就會造成其他線程一直被阻塞,造成效率的下降,所以上面兩種鎖只適合於很短小的局部上鎖。

unique_lock

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::unique_lock
#include <vector>

std::mutex mtx;           // mutex for critical section
void add(int &num, int &sum) {
	while (true) {
		std::unique_lock<std::mutex> lock(my_lock);
		if (num < 50) { //運行條件
			num += 1;
			sum += num;
		}
		else {
			break;
		}
		lock.unlock(); //釋放鎖

		Sleep(10);

		lock.lock();//再次上鎖,最後一次上鎖可以不用解鎖
		sum += num;
	}
}

int main() {
	int sum = 0;
	int num = 0;
	std::vector<std::thread> ver;   //保存線程的vector
	for (int i = 0; i < 20; ++i) {
		std::thread t = std::thread(add, std::ref(num), std::ref(sum));
		ver.emplace_back(std::move(t)); //保存線程
	}

	std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join
	std::cout << sum << std::endl;
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章