muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁。代码如下所示:

// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
//互斥锁
#ifndef MUDUO_BASE_MUTEX_H
#define MUDUO_BASE_MUTEX_H #include <muduo/base/CurrentThread.h>
#include <boost/noncopyable.hpp>
#include <assert.h>
#include <pthread.h> namespace muduo
{ class MutexLock : boost::noncopyable//继承自noncopyable,表示不可拷贝
{
public:
MutexLock() : holder_(0)//构造函数,将holder初始化为0,表示该锁没有被任何线程拥有
{
int ret = pthread_mutex_init(&mutex_, NULL);//初始化互斥锁
assert(ret == 0); (void) ret;
} ~MutexLock()//析构函数
{
assert(holder_ == 0);//断言该锁没有被任何线程占用,才可以销毁
int ret = pthread_mutex_destroy(&mutex_);
assert(ret == 0); (void) ret;
} bool isLockedByThisThread()//是否当前线程拥有该锁
{
return holder_ == CurrentThread::tid();//只需判断当前线程的tid是否等于holder_
} void assertLocked()//断言当前线程拥有该锁
{
assert(isLockedByThisThread());
} // internal usage
void lock()//加锁
{
pthread_mutex_lock(&mutex_);
holder_ = CurrentThread::tid();//将当前线程的tid保存至holder_
} void unlock()//解锁
{
holder_ = 0;//holder_清零
pthread_mutex_unlock(&mutex_);
}
//获取threadMutex对象
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
} private: pthread_mutex_t mutex_;//变量保存
pid_t holder_;//当前使用该锁的线程id
};
//MutexLockGuard类使用RAII技法封装,在实际应用中这个类更常用
class MutexLockGuard : boost::noncopyable
{
public:
//explicit只能显式调用
explicit MutexLockGuard(MutexLock& mutex): mutex_(mutex)
{//构造函数获取资源
mutex_.lock();
}
//在对象生存期结束的时候利用析构函数可以实现自动解锁
~MutexLockGuard()
{//析构函数释放资源
mutex_.unlock();
} private: MutexLock& mutex_;//整个对象结束的时候mutex_并没有结束(引用)
}; } // 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

测试程序分别使用集中不同的方式往向量中插入数据,从中也可以看出锁的开销,测试代码如下所示:


//互斥锁测试代码
#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;//int动态数组(向量)
const int kCount = 10*1000*1000;//常量1千万 void threadFunc()
{
for (int i = 0; i < kCount; ++i)
{
MutexLockGuard lock(g_mutex);//使用锁
g_vec.push_back(i);//往向量中插入1000w个整数
}
} int main()
{
const int kMaxThreads = 8;//最多8个线程
g_vec.reserve(kMaxThreads * kCount);//预留8千万个整数(这个所占的内存空间有300多M) Timestamp start(Timestamp::now());//当前时间戳
for (int i = 0; i < kCount; ++i)
{
g_vec.push_back(i);//往向量中插入1000w个整数
}
//输出插入这么多个数的时间
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)
{//ptr_vector指针的vector
boost::ptr_vector<Thread> threads;
g_vec.clear();//先清除g_vec向量
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();
}
//分别输出1到8个线程执行插入操作的时间
printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start));
}
}

单独编译后运行结果如下:

muduo网络库源码学习————互斥锁的更多相关文章

  1. muduo网络库源码学习————Timestamp.cc

    今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...

  2. muduo网络库源码学习————线程池实现

    muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的.线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也 ...

  3. muduo网络库源码学习————日志滚动

    muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...

  4. muduo网络库源码学习————无界队列和有界队列

    muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型.(这里以无界队列为例,有界队 ...

  5. muduo网络库源码学习————线程类

    muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...

  6. muduo网络库源码学习————条件变量

    muduo里的CountDownLatch类实际上是对条件变量condition进行的封装,既可以用于所有子线程等待主线程发起 "起跑" ,也可以用于主线程等待子线程初始化完毕才开 ...

  7. muduo网络库源码学习————原子性操作Atomic.h

    原子性操作可以做到比互斥锁更小的开销,在多线程编程中原子性操作是非常有用的.Atomic.h文件位于muduo/base下,代码如下: // Use of this source code is go ...

  8. muduo网络库源码学习————线程特定数据

    muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...

  9. muduo网络库源码学习————日志类封装

    muduo库里面的日志使方法如下 这里定义了一个宏 #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) ...

随机推荐

  1. Linux服务器架设篇,Nginx服务器的架设

    1.安装 nginx依赖包 (1)安装pcre yum install pcre-devel (2)安装openssl yum -y install openssl-devel (3)安装zlib y ...

  2. javascript 入门 之 bootstrap/bootstrap-table 安装方法

    也和select2一样,可以有三种方法 1.远程调用CDN 2.用bower安装 3.下载 时间原因,暂时先讲第二种,其余两种,以后完善 1.进入根目录,执行bower install bootstr ...

  3. 讲真,这两款idea插件,能治愈你英语不好的病

    时不时就有小伙伴问我,"二哥,能推荐一款 IDE 吗?"你看这话问的,现在搞 Java 的不都在用 Intellij IDEA 吗,还用得着推荐(我已经和 Eclipse 分手了) ...

  4. Python中关于字符串你应该知道这些...

    # Python中字符串的常见用法### 定义:带有双引号/单引号/三引号### 双引号:适用于所写的字符串里没有双引号的.例如:"凡是“辛苦”必是礼物"报错​### 单引号:适用 ...

  5. leetcode c++做题思路和题解(1)——常规题总结

    常规题总结 0. 目录 两数之和 1. 两数之和 耗时4ms(98.82%),内存6.2m. 两数之和--寻找中值向两边扩散法 1.1 思路 思路很简单,就是先找数组中target/2的前后两个值,然 ...

  6. HttpClient之Get请求和Post请求示例

    HttpClient之Get请求和Post请求示例 博客分类: Java综合   HttpClient的支持在HTTP/1.1规范中定义的所有的HTTP方法:GET, HEAD, POST, PUT, ...

  7. 面试 HTTP ,99% 的面试官都爱问这些问题

    HTTP 和 HTTPS 的区别 HTTP 是一种 超文本传输协议(Hypertext Transfer Protocol),HTTP 是一个在计算机世界里专门在两点之间传输文字.图片.音频.视频等超 ...

  8. 常用App用户体验找茬

    冯晓云: 哔哩哔哩手机客户端:视频播放只允许横屏全屏:还有长视频的“5分钟诅咒”,遇到网速不好的时候是个大写的悲剧: 必应词典UWP版本:主页新闻链接跳转后,一些页面不支持划词取译,当然本身各个页面也 ...

  9. ST表(求解静态RMQ问题)

    例题:https://www.acwing.com/problem/content/1272/ ST表类似于dp. 定义st[i][j]表示以i为起点,长度位2^j的一段区间,即[ i , i + 2 ...

  10. Python大数据与机器学习之NumPy初体验

    本文是Python大数据与机器学习系列文章中的第6篇,将介绍学习Python大数据与机器学习所必须的NumPy库. 通过本文系列文章您将能够学到的知识如下: 应用Python进行大数据与机器学习 应用 ...