从零开始构建一个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(;;)循环 ...
随机推荐
- Java获取指定时间段的年份(开始、结束时间)、月份(开始、结束时间)、天数(开始、结束时间)
package test; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleD ...
- “ORA-01747: user.table.column, table.column 或列说明无效” 的解决方案
此问题的原因是因为表的列名称使用了Oracle声明的关键字,列名起的不好引起的. 如果列很多,又不好确定是哪个列名使用了关键字,以下建议可供参考: select * from v$reserved_w ...
- 如何使用NSOperations和NSOperationQueues 第二部分
这篇文章还可以在这里找到 英语 以下是对上面代码的注解: 导入PhotoRecord.h文件,这样你就可以在下载成功后,单独地设置PhotoRecord变量的图片属性(image property). ...
- 【CV知识学习】神经网络梯度与归一化问题总结+highway network、ResNet的思考
这是一篇水货写的笔记,希望路过的大牛可以指出其中的错误,带蒟蒻飞啊~ 一. 梯度消失/梯度爆炸的问题 首先来说说梯度消失问题产生的原因吧,虽然是已经被各大牛说烂的东西.不如先看一个简单的网络结构 ...
- [Javascript] Use a custom sort function on an Array in Javascript
Sorting in Javascript with sort uses lexical sorting by default, which means it will sort in alphabe ...
- erlang 中文编码显示乱码问题
许久没做erlang开发了,近期有网友问到erlang的问题.就抽时间看下.问题是这种.模块有中文.将中文直接打印出来.shell下显示会出现乱码.但假设先将中文转成binary.就行正常显示出来. ...
- [转载]JSONP跨域的原理解析
JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略).这一策略对于Java ...
- 深入理解JVM:HotSpot虚拟机对象探秘
对象的创建 java是一门面向对象的语言.在Java程序执行过程中无时无刻有Java对象被创建出来.在语言层面上,创建对象(克隆.反序列化)一般是一个newkeyword而已,而在虚拟机中,对象的创建 ...
- Redis 事务及其应用
参考: http://www.runoob.com/redis/redis-transactions.html https://www.cnblogs.com/qlshine/p/5958504.ht ...
- hadoop报JAVA_HOME is not set暂时解决办法
直接在etc/hadoop/hadoop-env.sh中 export JAVA_HOME=XXX