最近在学习陈硕大神的muduo库,感觉写的很专业,以及有一些比较“高级”的技巧和设计方式,自己写会比较困难。

于是打算自己写一个简化版本的Reactor模式网络库,就取名叫mini吧,同样只基于Linux平台,不使用boost库,去掉一些比较复杂的部分,只实现比较基本的功能。

写作的过程中,参考了https://github.com/chenshuo/muduo(原始版本的实现),以及https://github.com/AlexStocks/muduo(去掉boost库的依赖,改用C++11)

就先从用于线程同步的互斥锁和条件变量的封装开始吧,基础部分还会包括一个很简单的日志类、线程封装和简单的线程池。

Linux环境下线程同步的方式有很多,互斥锁、读写锁、自旋锁、条件变量、屏障等都可以作为同步的方式,muduo库使用的是互斥锁+条件变量的方式,原因也很简单,就是简单易用,同时也不失高效性。

为了通用性,使用的都是POSIX的同步原语以及线程实现。

首先是对互斥量的封装:

 #ifndef MUTEX_H
#define MUTEX_H
#include <pthread.h>
namespace mini
{
//used as class member
class MutexLock
{
public:
MutexLock()
{
pthread_mutex_init(&mutex_,NULL);
}
~MutexLock()
{
pthread_mutex_destroy(&mutex_);
}
void lock()
{
pthread_mutex_lock(&mutex_);
}
void unlock()
{
pthread_mutex_unlock(&mutex_);
} pthread_mutex_t* getPthreadMutex()
{
return &mutex_;
} private:
pthread_mutex_t mutex_;
};
//used as RAII obj
class MutexLockGuard
{
public:
MutexLockGuard(MutexLock& mutex)
:mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard()
{
mutex_.unlock();
} private:
MutexLock& mutex_;
};
} #endif // MUTEX_H

MutexLock是对pthread_mutex的简单封装,包括初始化、加锁、解锁以及销毁,主要用作类的成员变量(比如Condition类、ThreadPool类等)。

MutexLockGuard是一个RAII类,构造时自动加锁,析构时自动解锁,一般用在整个过程都需要加锁的块内(比如一个作用于临界区的函数),可以避免忘记解锁引起的死锁。

然后是对于条件变量的封装:

 #ifndef CONDITION_H
#define CONDITION_H
#include "Mutex.h"
#include <pthread.h>
namespace mini
{
class Condition{
public:
Condition(MutexLock& mutex)
:mutex_(mutex)
{
pthread_cond_init(&cond_,NULL);
} ~Condition()
{
pthread_cond_destroy(&cond_);
} void wait()
{
pthread_cond_wait(&cond_,mutex_.getPthreadMutex());
} void notify()
{
pthread_cond_signal(&cond_);
} void notifyAll()
{
pthread_cond_broadcast(&cond_);
} private:
MutexLock& mutex_;//reference, not hold
pthread_cond_t cond_;
};
} #endif // CONDITION_H

Condition类是对pthread_cond的封装,因为条件变量本来就要与mutex配合使用,故而持有一个MutexLock的引用,主要操作是lock()、notify()和notifyAll()。

下面通过一个简单的例子来看看这两个类的使用:

 #include <iostream>
#include "Condition.h"
#include <unistd.h> using namespace std;
using namespace mini; mini::MutexLock mutex;
mini::Condition cond(mutex); int count=; void* threadFuncAdd(void*)
{
sleep();
cout<<"ThreadAdd run!"<<endl;
while(count<=)
count++;
cout<<"ThreadAdd finish!"<<endl;
cond.notify();
}
void* threadFuncPrint(void*)
{
mutex.lock();
while(count<=)
{
cout<<"ThreadPrint wait!"<<endl;
cond.wait();
} cout<<"ThreadPrint wake up!"<<endl;
} int main()
{
//count=0;
pthread_t p1,p2;
pthread_create(&p1,NULL,threadFuncAdd,NULL);
pthread_create(&p2,NULL,threadFuncPrint,NULL); sleep(); return ;
}

简单来说,主线程创建了两个线程,一个用来对count进行自加,一个用来等待count值到达100并输出一句话。为了确保print线程会先等待条件,让add线程睡眠了1s。

结果与预期一致,threadprint先进入等待状态,然后threadadd开始执行,并在count自加到1000后,notify() threadprint,threadprint被唤醒。

从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition的更多相关文章

  1. 从零开始构建一个Reactor模式的网络库(二)线程类Thread

    线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的. 首先是CurrentThread命名空间,主要是获取以及缓存线程id: #if ...

  2. 从零开始构建一个的asp.net Core 项目

    最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到"He ...

  3. 从零开始构建一个centos+jdk7+tomcat7的docker镜像文件

    从零开始构建一个centos+jdk7+tomcat7的镜像文件 centos7系统下docker运行环境的搭建 准备centos基础镜像 docker pull centos 或者直接下载我准备好的 ...

  4. 从零开始构建一个的asp.net Core 项目(一)

    最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到“Hello W ...

  5. 2021 从零开始打造一个自己的 UI 组件库

    2021 从零开始打造一个自己的 UI 组件库 refs GUI https://github.com/xgqfrms/gui/ https://www.npmjs.com/package/@xgqf ...

  6. [计算机视觉]从零开始构建一个微软how-old.net服务/面部属性识别

    大概两三年前微软发布了一个基于Cognitive Service API的how-old.net网站,用户可以上传一张包含人脸的照片,后台通过调用深度学习算法可以预测照片中的人脸.年龄以及性别,然后将 ...

  7. 从零开始构建一个的asp.net Core 项目(二)

    接着上一篇博客继续进行.上一篇博客只是显示了简单的MVC视图页,这篇博客接着进行,连接上数据库,进行简单的CRUD. 首先我在Controllers文件夹点击右键,添加->控制器 弹出的对话框中 ...

  8. .Net 从零开始构建一个框架之基本实体结构与基本仓储构建

    本系列文章将介绍如何在.Net框架下,从零开始搭建一个完成CRUD的Framework,该Framework将具备以下功能,基本实体结构(基于DDD).基本仓储结构.模块加载系统.工作单元.事件总线( ...

  9. 构建一个基于事件分发驱动的EventLoop线程模型

    在之前的文章中我们详细介绍过Netty中的NioEventLoop,NioEventLoop从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环 ...

随机推荐

  1. KernelHacking

    https://kernelnewbies.org/KernelHacking-HOWTO/Debugging_Kernel

  2. 同一页面引入多个JS文件的编码问题

    原来只是觉得IE解析HTML文件的时候,需要知道其传输编码,才能正确处理,而从来没有在意过JavaScript文件的编码问题.结果今天发现同一页面中的多个JavaScript文件如果保存编码不同,也会 ...

  3. HDU 1257 最少拦截系统(dp)

    Problem Description 某国为了防御敌国的导弹突击,发展出一种导弹拦截系统.可是这样的导弹拦截系统有一个缺陷:尽管它的第一发炮弹可以到达随意的高度,可是以后每一发炮弹都不能超过前一发的 ...

  4. The most widely used name server software: BIND

    https://www.isc.org/downloads/bind/ The most widely used name server software: BIND BIND is open sou ...

  5. 当电视沦为“情怀”,5G能不能拯救它?(zz)

    文|佘凯文 来源|智能相对论(aixdlun) 现阶段,智能家居行业极度期待5G的到来,甚至超过手机.行业对于颠覆性的升级的欲望极其强烈,纵观整个智能家居行业,除了像智能音箱外的偶尔单品能够“引爆”市 ...

  6. 光流(optical flow)和openCV中实现

    转载请注明出处! ! ! http://blog.csdn.net/zhonghuan1992 光流(optical flow)和openCV中实现 光流的概念:        是Gibson在195 ...

  7. 「翻译」Unity中的AssetBundle详解(一)

    AssetBundles AssetBundle是一个存档文件,其中包含平台在运行时加载的特定资产(模型,纹理,预制,音频剪辑,甚至整个场景).AssetBundles可以表示彼此之间的依赖关系;例如 ...

  8. vmware Ubuntu忘记登录密码

    VMware Workstation 上的Ubuntu 11.10 登录时,用户密码忘记了,以下是我对此问题解决的方法: 1)重新启动Ubtuntu 16 系统,同时长时间按住(或连续点击)esc键进 ...

  9. UICollectionView基础用法

    初始化部分: UICollectionViewFlowLayout *flowLayout= [[UICollectionViewFlowLayout alloc]init]; self.myColl ...

  10. Why you shouldn’t connect your mobile application to a database

    BY CRAIG CHAPMAN · PUBLISHED 2015-07-02 · UPDATED 2015-07-02   Working at Embarcadero, I frequently ...