Mutex互斥量:muduo库中的封装为MutexLock类与MutexLockGuard类。
类图:
继承boost::noncopyable,对象语义不能拷贝,该类主要是对一系列系统线程函数pthread_mutex_XXX的封装。
私有数据成员:
mutex_:存储linux线程互斥量pthread_mutex_t
holder_:存储拥有该锁的线程的tid
公有成员函数:
isLockedByThisThread:当前线程是否拥有该锁
assertLocked:断言当前线程锁拥有该锁
Lock:加锁
Unlock:解锁
getPthreadMutex:获取线程互斥量指针
类图:
MutexLockGuard类使用RAII技法封装了MutexLock对象,方便使用者对互斥量的使用(构造函数中加锁,析构函数中解锁)
构造函数前的explict可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。
例如:
还有一个需要注意的是:Mutexlockguard与mutexlock仅仅是关联关系,没有整体与局部关系(有就是聚合),也不负责对象的生存期,如果存在整体与局部关系并且负责对象生存期则是组合关系。
此外,为避免用户错误使用,定义宏:#define MutexLockGuard(x) error "Missing guard object name"
使用示例:
//#include <muduo/base/CountDownLatch.h>
#include <muduo/base/Mutex.h>
#include <muduo/base/Thread.h>
#include <muduo/base/Timestamp.h>
#include <boost/bind.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <vector>
#include <stdio.h>
using namespace muduo;
using namespace std;
MutexLock g_mutex;
vector<int> g_vec;
const int kCount = 10*1000*1000;
void threadFunc()
{
for (int i = 0; i < kCount; ++i)
{
MutexLockGuard lock(g_mutex);
//定义MutexLockGuard对象lock,构造函数中对g_mutex加锁,
//析构函数中对g_mutex解锁,避免手动加解锁的失误
g_vec.push_back(i);
}
}
int main()
{
const int kMaxThreads = 8;//最多8个线程
g_vec.reserve(kMaxThreads * kCount);
Timestamp start(Timestamp::now());
for (int i = 0; i < kCount; ++i)
{
g_vec.push_back(i);
}
printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start));
start = Timestamp::now();
threadFunc();
printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start));
for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads)
{
boost::ptr_vector<Thread> threads;
g_vec.clear();
start = Timestamp::now();
for (int i = 0; i < nthreads; ++i)
{
threads.push_back(new Thread(&threadFunc));
threads.back().start();
}
for (int i = 0; i < nthreads; ++i)
{
threads[i].join();
}
printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start));
}
}
该例子主要再同样操作情况下,比较单个线程不加锁与加锁的执行时间以及多个线程加锁的执行时间。
对示例中的boost::ptr_vector进行说明: