Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
为了方便Poller的管理,Muduo定时器是基于文件描述符实现。
实现
定时器提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
为了方便Poller的管理,Muduo定时器是基于文件描述符实现。
定时器提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
与base文件夹下的通用线程池相比,EventLoopThreadPool更加专门化,专为为EventLoopThread而生,专为EventLoop而生,专为One Loop Per Thread而生,专为网络事件驱动而生,专为Muduo而生!
提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
终于到了Muduo网络库最最核心的部分,这里还是建议大家亲自看看源码。源码很好读,博客最多起到辅助作用。因为EventLoop和Thread是绑定的,所以,可能这两部分放在一起更适合。
了解ExevntLoop和Thread后,对One Loop Per Thread思想,就有了一个大体的轮廓,这种设计思想,真的很高效,因为,每个线程都有自己的资源,比如epoll、IO事件处理,定时器、任务队列等。每个线程内部资源都是自我维护的(自己的事情自己做), 除了对线程的任务队列进行操作时有一段极小的临界区需要加锁外,不涉及任何锁的竞争。这里为每个线程设置自己的任务队列的思想特别关键,正是利用每个线程只处理自己任务队列里面的回调任务,实现了将并行任务串行化的效果。 将原本的并发(涉及线程安全,需要加锁)操作,封装成任务(无需加锁)回调,添加到各自的任务队列中,交给线程自己处理。实现了线程的隔离、无锁化编程,巧妙的利用单线程天生串行执行的优势。活该Muduo高性能、高并发。
提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
简单讲,Channel就是对文件描述符(fd)的封装,进行事件管理,将fd和对其操作的回调封装在一起,方便,在fd上有IO事件到来时,利用相应的回调来处理IO事件;Poller就是对Linux下各种IO多路复用进行抽象,提供一个统一的接口,该类是一个虚基类。路径./net/poller中的源码,就是对Poller的实现,包括:EPollPoller、PollPoller。
这部分源代码很朴实易懂,代码量也不大,建议读者,亲自看看源码。
提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
Muduo的异步日志支持:异步日志输出,日志回滚。本文重点在异步日志输出,主要集中在AsyncLogging.cc文件的实现,至于日志回滚,属于文件IO管理范畴,不会细讲,这部分的代码主要集中在LogFile.cc、FileUtil.cc文件,代码量也不大,感兴趣的读者可以自行深入阅读。
Muduo异步日志的实现是典型的多对一的,多生产者,单消费者模型。简单来说就是程序中的多个线程(前台线程)产生日志,然后由一个日志同步线程(后台线程)消化日志,将日志同步给磁盘。
术语纠正
阅读过Muduo源码的朋友都应该知道,Muduo实现的异步日志是双缓冲的,但是我阅读过很多Muduo有关异步日志的博客,有的人说Muduo里面双缓冲指的是currentBuffer_和nextBuffer_两块缓存,也有人说,Muduo的双缓冲是指前台的缓存和后台线程的缓存。
查阅资料得知:
定义: 双缓冲技术是一种通过使用两个缓冲区(buffers)来实现某种功能的技术。通常,这两个缓冲区会交替使用,一个用于写入数据,另一个用于读取数据,或者在某种操作完成后进行交换。
在不同的领域中,双缓冲技术有不同的应用,以下是一些常见的应用场景:
图形学: 在图形学中,双缓冲技术通常用于解决图像闪烁的问题。一个缓冲区用于显示当前图像,而另一个缓冲区则用于在后台绘制下一帧图像。当绘制完成后,两个缓冲区进行交换,确保只显示完整的图像,从而避免了闪烁。
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
闲聊
Muduo对线程和线程池的封装,涉及得到源码也不多,大概加一起300多行,这部分读者可以好好精读一下。
在阅读cpp的源码,分析一个类具体的实现的时候,首先应该看类的.h文件,主要看类的成员变量有哪些,毕竟成员函数,就是对成员变量进行代码层面的操作的。
提供的接口:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
闲聊
首先感慨一句,muduo库对C语言原生的线程安全以及同步的API的封装,真的称得上是教科书式的,非常精妙、规范,很值得学习。
读者在阅读muduo源码的时候,看到类定义的类名称被一些宏定义修饰、以及类的成员变量被一些宏定义修饰时,可以直接忽略,无视这些宏。因为这些东西的存在完全不影响整体的功能。简单来说就是吓唬人的。不仅如此,在看muduo以及其他的源码的时候,我们没必要转牛角尖,死扣细节,对于一个类,如果我们可以猜到他的功能以及怎么实现的,我们可以直接看他在源码中的使用即可,没必要在这细节上面浪费精力,专注整体架构,以及思想,不太过专注细节,才是阅读一份源码的正确套路。
提到原子操作,不得不顺便提一下c++ std::atomic的原子操作以及它的内存序,这个知识点,以后的博客再来记录。
这里是muduo对gcc提供的原子操作api的封装:
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
Muduo源码笔记系列:
muduo源码阅读笔记(2、对C语言原生的线程安全以及同步的API的封装)
muduo源码阅读笔记(6、ExevntLoop和Thread)
muduo源码阅读笔记(7、EventLoopThreadPool)
前言
Muduo的日志设计的非常简单,日志的格式是固定的,一条日志包括:[日志头,日志体,日志尾]。实际上,参考工业级日志的使用来看,日志还应该能支持格式变更,即用户可以自定义日志的格式,选择自己关心的日志条目进行输出,或者在日志中添加一些额外的字符来修饰日志。考虑到Muduo的核心是网络库,而不是日志库,这些点就不过多深入讨论。
Impl::stream_
(简化日志的使用方式(宏定义 + 临时对象的编程技巧)调用匿名对象的stream()
成员函数,会返回一个类型为LogStream的引用也即Impl::stream_
对象本身,muduo对LogStream
类进行了详细的>>
操作符重载,这部分代码简单易读,就不详细赘述了,这样就能将字符串类型/数值类型的数据使用>>
操作符输出到Impl::stream_
上(类似std::cout的使用)
日志消息体的输出: