muduo源码
听说西佳佳难得很
要学的有好多……
是自己的功课,在这里没有必要欺骗自己,要好好弄懂在记录的知识点。感受到孤单的时候也要向前,努力成为最完善,最有力,最强大的自己。
展开
-
muduo net库学习笔记8——件驱动循环线程池EventLoopThreadPool
感谢并转载自https://blog.csdn.net/sinat_35261315/article/details/78376821线程池的作用体现在用户启动TcpServer服务器时创建大量子线程,每个子线程创建一个EventLoop并开始执行EventLoop::loop主线程的线程池保存着创建的这些线程和EventLoop当Acceptor接收到客户端的连接请求后返回TcpServer,TcpServer创建TcpConnection用于管理tcp连接TcpServer从事件驱动线程池中转载 2020-08-14 08:06:04 · 287 阅读 · 4 评论 -
muduo net库学习笔记7——用于创建服务器的类TcpServer
muduo为每个EventLoop设计了runInLoop和queueInLoop函数用来将本该在其他线程执行的线程不安全函数放到它所属线程执行,从而达到线程安全。muduo采用采用one loop per thread的设计思想,即每个线程运行一个循环,这里的循环也就是事件驱动循环EventLoop。所以,EventLoop对象的loop函数,包括间接引发的Poller的poll函数,Channel的handleEvent函数,以及TcpConnection的handle*函数都是在一个线程内完成的。而原创 2020-08-13 21:58:43 · 249 阅读 · 1 评论 -
muduo net库学习笔记6——缓冲区Buffer及TcpConnection的读写操作
在tcp的通信过程中,内核其实为tcp维护着一个缓冲区当调用write/send时,会向内核缓冲区中写入数据,内核和tcp协议栈负责将缓冲区中的数据发送到指定<ip,port>的目标位置。当有数据到达内核的tcp缓冲区中,如果开启了对套接字可读事件的监听,那么内核会让套接字变为可读状态,从而从poll函数中返回,调用read/recv进行读操作但是,内核维护的tcp缓冲区通常都比较小如果调用write/send时,内核缓冲区已满,那么阻塞io将会阻塞在io函数上直到内核缓冲区有足够转载 2020-08-13 17:32:41 · 427 阅读 · 0 评论 -
muduo net库学习笔记5——服务器监听类Acceptor、Tcp连接(优雅关闭连接)、TcpConnection的建立与关闭
简单回顾一下Channel和TcpConnection的关系Channel的回调函数就是根据被激活原因调用不同的回调函数, 这些回调函数是在TcpConnection创建时就被设置的每个TcpConnection对象代表一个tcp连接,所以每个TcpConnection中需要保存用于服务器/客户端通信的套接字,这个套接字就记录在Channel中TcpConnection在创建之初就会为Channel设置回调函数,如果套接字可读/可写/错误/关闭等就会执行TcpConnection的函数TcpCon原创 2020-08-13 14:58:53 · 631 阅读 · 0 评论 -
muduo net库学习笔记4——事件驱动循环EventLoop、runInLoop和queueInLoop及对应唤醒
首先总体情况:每个muduo网络库有一个事件驱动循环线程池 EventLoopThreadPool,线程池用在事件驱动循环上层,也就是事件驱动循环是线程池中的一个线程每个TcpServer对应一个事件驱动循环线程池每个线程池中有多个事件驱动线程EventLoopThread每个线程运行一个Eventloop事件循环每个EventLoop事件循环包含一个IO复用Poller, 一个计时器队列TimerQueue每个Poller监听多个Channel, 也就对应一个TcpConnection或者监原创 2020-08-12 23:34:45 · 1421 阅读 · 0 评论 -
muduo net库学习笔记3——定时器的实现
在常见的定时函数中muduo选择timerfd实现定时器,原因如下:sleep / alarm / usleep在实现时有可能使用了SIGALRM信号,多线程程序中尽量避免使用信号,因为处理起来比较麻烦(信号通知进程,所有线程都将接收到这个信号,谁处理好)。另外,如果网络库定义了信号处理函数,用户代码(main函数等使用库的程序)也定义了信号处理函数,这不就冲突了,该调用哪个好nanosleep / clock_nanosleep是线程安全的,但是会让当前线程挂起等待一段时间,这会导致线程失去响应。在原创 2020-07-19 08:11:20 · 517 阅读 · 4 评论 -
muduo net库学习笔记2——muduo网络库相关类图的关系、EventLoop、Channel、 Poller
Acceptor接收到客户端请求,调用TcpServer回调函数TcpServer回调函数中创建TcpConnection对象,代表着一个Tcp连接TcpConnection构造函数中创建Channel对象,保存客户端套接字fd和关心的事件(可读)Channel 注册自己到所属事件驱动循环(EventLoop)中的Poller上Poller开始监听,当发现Channel被激活后将其添加到EventLoop的激活队列中EventLoop在poll返回后处理激活队列中的Channel,调用其处理函数原创 2020-07-18 10:56:16 · 634 阅读 · 3 评论 -
muduo net库学习笔记1——TCP网络编程的本质、 EchoServer类、EventLoop类的简化封装
TCP网络编程最本质是处理三个半事件1,连接建立:服务器accept接收连接,客户端发起连接2,连接断开:主动断开(close、shutdown),被动断开(read返回0)3,消息到达:文件描述符可读4,消息发送完毕:这算半个。对于低流量的服务,可不关心这个事件;这里的发送完毕是指数据写入操作系统缓冲区,将由TCP协议栈负责数据的发送与重传,不代表对方已经接收到数据在接收缓冲区内:当一个套接字有数据到来的时候,会先被内核接收,网络库的可读事件就被触发,可读事件触发将数据从内核缓冲区移动到应用层原创 2020-07-17 21:52:04 · 301 阅读 · 0 评论 -
muduo base库学习笔记 10——日志类封装详解
日志的作用:1,开发过程中,有助于调试错误,能更好地理解程序2,运行过程中,日志能帮助我们诊断系统故障并处理、记录系统运行状态这代码就优点长了喔日志级别 TRACE 指出比DEBUG粒度更细的一些信息时间(开发过程中使用) DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的(开发过程中使用 INFO 表明消息在粗粒度级别上突出强调应用程序的运行过程 WARN 系统能正常运行,但可能会出现潜在错误的情形 ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行 FATAL 指原创 2020-07-17 15:26:39 · 392 阅读 · 0 评论 -
muduo base库学习笔记 9——线程特定数据、线程本地当地类封装
线程特定数据了解线程特定数据⭐在单线程程序中,经常要用到“全局变量”以实现多个函数间共享数据。在多线程环境下,由于数据空间是共享的,全局变量也是所有线程所共有的。但有时应用程序设计中有必要提供线程私有的全局变量,即仅在某个线程中有效,但却可以跨多个函数访问POSIX线程库通过维护一定的数据结构来解决这个问题,这个数据成为Thread-specific Data或TSD,线程特定数据也称为线程本地存储TLS(Thread-local storage)线程特定的数据结构????:一旦一个线程创建了原创 2020-07-16 20:33:15 · 185 阅读 · 1 评论 -
muduo_base库学习笔记8——线程安全的单例类实现、pthread_once、atexit、typedef char T_must_be_<font color = orange>compl..
了解单例模式:实际应用中,有些对象,我们只需要一个就可以了,比如,一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中只有一个打印程序的实例。单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。关于pthread_once#include <pthread.h>int pthread_once(pthread_on原创 2020-07-16 16:54:35 · 296 阅读 · 0 评论 -
muduo_base库学习笔记7——无界队列、有界队列及线程池的实现
BlockingQueue和BoundedBlockingQueue实质就是一个生产者消费者的模型, 可以用信号量也可以用条件变量BlockingQueue只用了一个条件变量notEmpty_,不需要notFull_,因为无界嘛不用考虑满的情况,条件变量需要跟一个互斥量一起使用mutex_,队列直接用STL中的deque_put()生产;生产中用MutexLockGuard调用Mutex_进行保护,生产了就通知消费者线程take()消费;队列空的时候就等待,直到不为空跳出循环,能跳出循环那就原创 2020-07-15 23:59:38 · 1011 阅读 · 6 评论 -
muduo_base库学习笔记6——互斥量、条件变量和倒计时门闩类
muduo中对互斥量和条件变量的操作基本上都是调用它们对应的相关函数来实现的,例如MutexLock::lock即调用pthread_mutex_lock(), Condition::wait()即调用pthread_cond_wait等互斥量muduo封装了MutexLock和MutexLockGuardMutexLock封装临界区,它是一个简单的资源类,用RAII手法封装互斥量的创建与销毁,一般是别的类的数据成员MutexLockGuard封装临界区的进入和退出,即加锁和解锁,它一般是个栈上对象原创 2020-07-15 22:50:17 · 243 阅读 · 0 评论 -
muduo学习笔记5——线程封装
线程标识符pthread_selfgettid __thread, gcc内置的线程局部存储设施__thread只能修饰POD类型, plain old data pthread_atfork线程标识符Linux中,每个进程有一个pid,类型为pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型为pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)...原创 2020-07-15 17:30:34 · 221 阅读 · 0 评论 -
muduo学习笔记4——原子性操作和Atomic.h、Exception类的实现
所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。在多进程(线程)访问资源时,能够确保所有其他的进程(线程)都不在同一时间内访问相同的资源。C/C++ 中数值操作,如自加 (n++) 自减 (n- -) 及赋值 (n=2) 操作都不是原子操作。如果多线程程序需要使用全局计数器,程序就需要使用锁或者互斥量保证操作的安全性,对于较高并发的程序,这种做法会造成一定的性能瓶颈。gcc提供的常用原子性操作// 原原创 2020-07-15 11:24:06 · 252 阅读 · 0 评论 -
muduo3学习笔记——Timestamp.{h,cc}
首先代码中的一些要点:(1)Timestamp类继承自boost::less_than_comparable 模板类只要实现 <,即可自动实现>,<=,>=(2)使用到了BOOST_STATIC_ASSERT,编译时断言;(3)gmtime和gmtime_r函数(4)函数参数采用值传递(5)使用PRId64(6)对象语义和值语义可以看谱哥笔记,然后就开始数据结构啦放源码截图继承自两个基类:muduo::copyable这是一个空基类,起到一个标识作用,用来标识凡原创 2020-07-14 11:24:05 · 328 阅读 · 0 评论 -
muduo2——编程风格:面向对象的编程和基于对象的编程(下)
回顾面向对象的编程风格封装线程类,一般这么做:写一个Thread base class,含有(纯)虚函数Thread::run(),然后应用程序派生一个derived class,覆写run()。程序里的每一种线程对应一个Thread的派生类。面向对象的编程风格主要还是围绕面向对象的三大特点“封装、继承、多态”来展开的——通过封装隐藏实现细节,只暴露需要对外提供的属性或方法;通过继承的特性来提高程序的可复用性;定义抽象基类(纯虚函数),让其派生类继承并实现它的接口方法。“面向对象”和“基于对象”都实现了原创 2020-07-11 23:40:34 · 207 阅读 · 0 评论 -
muduo1——编程风格:面向对象的编程和基于对象的编程(上)
muduo库其实不是面向对象的编程,而是基于对象的编程,那么在进入正式的muduo源码分析之前,先来看看这两种编程风格一、面向对象编程风格通过对一个线程类的封装来进行讲解:Thread是一个抽象类不能实例化对象,TestThread是派生类一个具体类;每一种线程类是有一个自己的执行体,用Run表示,不同的线程类其执行体是不一样的,就将这个方法提升到基类做一个抽象的接口代码简单示例/*Thread.h*/#ifndef _THREAD_H_#define _THREAD_H_#includ原创 2020-07-11 17:52:32 · 274 阅读 · 0 评论