从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition
最近在学习陈硕大神的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的更多相关文章
- 从零开始构建一个Reactor模式的网络库(二)线程类Thread
线程类Thread是对POSIX线程的封装类,因为要构建的是一个Linux环境下的多线程网络库,对线程的封装是很必要的. 首先是CurrentThread命名空间,主要是获取以及缓存线程id: #if ...
- 从零开始构建一个的asp.net Core 项目
最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到"He ...
- 从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
从零开始构建一个centos+jdk7+tomcat7的镜像文件 centos7系统下docker运行环境的搭建 准备centos基础镜像 docker pull centos 或者直接下载我准备好的 ...
- 从零开始构建一个的asp.net Core 项目(一)
最近突发奇想,想从零开始构建一个Core的MVC项目,于是开始了构建过程. 首先我们添加一个空的CORE下的MVC项目,创建完成之后我们运行一下(Ctrl +F5).我们会在页面上看到“Hello W ...
- 2021 从零开始打造一个自己的 UI 组件库
2021 从零开始打造一个自己的 UI 组件库 refs GUI https://github.com/xgqfrms/gui/ https://www.npmjs.com/package/@xgqf ...
- [计算机视觉]从零开始构建一个微软how-old.net服务/面部属性识别
大概两三年前微软发布了一个基于Cognitive Service API的how-old.net网站,用户可以上传一张包含人脸的照片,后台通过调用深度学习算法可以预测照片中的人脸.年龄以及性别,然后将 ...
- 从零开始构建一个的asp.net Core 项目(二)
接着上一篇博客继续进行.上一篇博客只是显示了简单的MVC视图页,这篇博客接着进行,连接上数据库,进行简单的CRUD. 首先我在Controllers文件夹点击右键,添加->控制器 弹出的对话框中 ...
- .Net 从零开始构建一个框架之基本实体结构与基本仓储构建
本系列文章将介绍如何在.Net框架下,从零开始搭建一个完成CRUD的Framework,该Framework将具备以下功能,基本实体结构(基于DDD).基本仓储结构.模块加载系统.工作单元.事件总线( ...
- 构建一个基于事件分发驱动的EventLoop线程模型
在之前的文章中我们详细介绍过Netty中的NioEventLoop,NioEventLoop从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环 ...
随机推荐
- MySQL 为日期增加一个时间间隔
set @dt = now(); select date_add(@dt, interval 1 day); - 加1天 select date_add(@dt, interval 1 hour) ...
- http://www.cnblogs.com/shihaiming/
原文:http://www.bubuko.com/infodetail-917303.html 右击项目,点击Run as,如下图: 即可看到有很多现有的maven命令,点击即可运行,并在控制台可以看 ...
- argument to nsmutablearray method addobject cannot be nil 警告
You cannot add nil to an NSMutableArray, and you will raise an exception if you try to. There's NSNu ...
- linux shell操作
---------------------------------------------------- 原文:http://unix.stackexchange.com/questions/2863 ...
- vim列块操作
一.可视模式 进入可视模式有三种方法:v,V,CTRL+V (1)按v启用可视模式,能够按单个字符选择内容,移动光标能够选择. 如: (2)按V启用可视模式,立马选中光标所在行.按单行符选择内容.移动 ...
- Handlebars的基本用法 Handlebars.js使用介绍 http://handlebarsjs.com/ Handlebars.js 模板引擎 javascript/jquery模板引擎——Handlebars初体验 handlebars.js 入门(1) 作为一名前端的你,必须掌握的模板引擎:Handlebars 前端数据模板handlebars与jquery整
Handlebars的基本用法 使用Handlebars,你可以轻松创建语义化模板,Mustache模板和Handlebars是兼容的,所以你可以将Mustache导入Handlebars以使用 Ha ...
- OpenStack源码系列---nova-api
OpenStack源码实际上是比较规范的,但是对刚刚接触到源代码的人来说,却感觉有点混乱.我刚开始的时候也常常搞乱,比如service.Service类继承自openstack.common.serv ...
- Arcgis Engine(ae)接口详解(6):workspace操作
//此处用的workspace来源与用户选择 IWorkspace workspace = null; //workspace一般等同于数据库 //工作空间类型,也可理解为数据库类型 //esriFi ...
- LINQ体验(18)——LINQ to SQL语句之视图和继承支持
视图 我们使用视图和使用数据表类似,仅仅需将视图从"server资源管理器/数据库资源管理器"拖动到O/R 设计器上,自己主动能够创建基于这些视图的实体类.我们能够同操作数据表一样 ...
- Scrapy 'module' object has no attribute 'Spider'错误
在“Scrapy入门教程”中,在创建的“dmoz_spider.py”文件中是通过 import scrapy class DmozSpider(scrapy.Spider): 的方式导入.但是用这种 ...