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;
}

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