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