文章目录BUG 描述set / map 的 insert / emplace 的返回值set / map 的去重于是 BUG 就诞生了 :strict weak ordering!!! BUG 描述 记录一个纠结了一天的 BUG: 向 set 容器中添加自定义类, 然后发现并没有添加进去, 真的是头大, 排查发现告诉我已经有相同 key 值元素存在了, 可我明明两个值不同 set / map 的 insert / emplace 的返回值 c++11 标准引入了 emplace, 与 insert 相对应. empalce 操作构造而不是拷贝元素。 当我们调用 insert 时, 我们将元素类型的对象传递给它们, 这些类型被拷贝到容器中 当我们调用 emplace, 会在容器管理的内存空间内直接创建对象。 注: emplace 的参数根据元素的类型变化, 参数必须与元素类型的构造函数相匹配 insert 和 emplace 只有在关键值 key 在容器中不存在时, 才会把该元素插入容器中, 否则如果 继续阅读 >>


吕子健 19/01/20 00:36:29
文章目录前言进程概念线程概念地址空间通信手段调度和切换进程何时调度线程切换进程的创建过程fork 函数task_struct父子进程间的文件共享线程的实现一对一模型 (内核级线程) 1:1多对一模型 (用户级线程) M:1多对多模型 两级模型 M:N 前言 书本上的定义: 线程是调度的基本单位, 进程是资源分配的基本单位 应该大家都知道这个概念, 但是进程和线程之间的异同绝不仅仅是这一句话这么简单 进程概念 进程是由正文段 (存放被执行的机器指令), 用户数据段 (存放进程在执行时直接进行操作的所有数据, 包括进程使用的全部变量在内), 系统数据段 (存放程序运行的环境) 而这个所谓的系统数据段也正是进程中最重要的一部分, 它就是进程和程序的区别所在, 进程作为一个动态的程序实例, 这一部分就存放着进程的控制信息, 每个进程都有一个 task_strust 数据结构 (也就是 PCB) 来存放这些控制信息. 操作系统也是通过这些控制信息 (task_struct) 来控制调度所有进程的 线程概念 继续阅读 >>


吕子健 19/01/19 20:36:07
吐槽部分 你以为你以为的就是你以为的么… 今天重新看了一下 muduo 的定时器实现的源码部分, 才发之前的理解是错, 之前只是停留在 muduo 的定时器是 timerfd 是实现的, 没有再去往下看, 今天重新捡起来看了一下源码, 才发现以前的理解错了 muduo 定时器 muduo 定时器封装了 Timer.h 里面保存的是超时时间和回调函数, TimerQueue.h 使用set容器保存多个定时器, 然后在TimerQueue中使用timerfd_create创建一个timerfd句柄, 插入定时器A后先比较A的触发时间和TimerQueue的触发时间, 如果A的触发时间比其小就使用timerfd_settime重置TimerQueue的timerfd的触发时间, TimerQueue中的timerfd的触发时间永远与保存的定时器中触发时间最小的那个相同, 然后timerfd触发可读后, 遍历保存的多个定时器, 看看有没有同时到期的, 有执行回调函数 继续阅读 >>


吕子健 19/01/04 22:48:13
文章目录Connector classConnector.hConnector.ccTcpClientTcpClient.hTcpClient.cc判断连接建立成功 Connector class Connector class负责主动发起连接, 他不单独使用, 而是包含在TcpClient class内, Connector不负责创建 socket, 只负责连接的建立, 包括这其中的错误处理和重连 需要考虑的难点: socket 是一次性的, 当 connect 出错, 我们必须关闭该 socket, 重新创建一个 socket, 但是Connector是可以反复使用的, 错误码和Acceptor不同, EAGAIN 是真的出错了, 表明本机临时端口暂时用完了( ephemeral port ), 需要延期重试, “正在连接” 的的返回码是 EINPROGRESS, 重试的间隔应该逐渐延长, 需要处理自连接 Connector.h #ifndef MUDUO_NET_CONNECTOR_H # 继续阅读 >>


吕子健 18/12/19 16:14:02
文章目录功能描述TcpConnection.hTcpConnection.cc 功能描述 TcpConnection class用来表示一个 TCP 连接, 不可再生, 如果这个连接断开, 那么该TcpConnection就失去了意义 TcpConnection中包含有封装好的读写 buffer, 用来收发数据 TcpConnection的生命周期由智能指针shared_ptr来管理, 具体在下面的注释中有 TcpConnection对象有四个状态, 表示连接的正在建立, 建立完成, 处于断开 (TcpConnection不主动关闭一个连接, 都是等客户端主动关闭), 已经断开 TcpConnection.h #ifndef MUDUO_NET_TCPCONNECTION_H #define MUDUO_NET_TCPCONNECTION_H #include <muduo/base/noncopyable.h> #include <muduo/base/StringPiece.h 继续阅读 >>


吕子健 18/12/18 21:40:11
文章目录AcceptorAcceptor.hAcceptor.ccTCPServerTCPServer.hTCPServer.cc Acceptor Acceptor class用来接收一个新的 TCP 连接 Acceptor.h #ifndef MUDUO_NET_ACCEPTOR_H #define MUDUO_NET_ACCEPTOR_H #include <functional> #include <muduo/net/Channel.h> #include <muduo/net/Socket.h> namespace muduo { namespace net { class EventLoop; class InetAddress; /// /// Acceptor of incoming TCP connections. /// class Acceptor : noncopyable { public: typedef std:: 继续阅读 >>


吕子健 18/12/17 20:42:15
文章目录功能Thread classThread.hThread.ccEventLoopThreadEventLoopThread.hEventLoopThread.ccEventLoopThreadPoolEventLoopThreadPool.hEventLoopThreadPool.cc 本来没想看这一块, 但是看TCPServer class的时候里面用到了, 所以先总结一下这两个类的封装 功能 这三个类并不难理解, 没有很复杂的逻辑, 是对一些操作的简单封装 前面说了只要创建运行了EventLoop的线程就是 IO 线程, EventLoopThread是对 IO 线程的封装, EventLoopThreadPool是 IO 线程池, 负责创建和分发 IO 线程, Thread class 介绍EventLoopThread之前, 先介绍一下Thread class, 在EventLoopThread有一个Thread类的对象 Thread.h #ifndef MUDUO_BASE_THR 继续阅读 >>


吕子健 18/12/15 17:27:05
文章目录EventLoop::runInLoop 函数功能eventfd 的使用创建eventfd 示例代码EventLoop::runInLoop源码分析如何使用该功能 EventLoop::runInLoop 函数功能 在上一篇博客介绍了 muduo 的核心主循环EventLoop::loop函数, 在 muduo 中, 还有一个十分好用的功能: 可以执行其他线程的任务, 因为平时 IO 线程都阻塞在EventLoop::loop函数的poll函数中, 为了让空闲的 IO 线程也能利用起来, 某一个(IO线程或者其他)线程可以执行一个任务调用EventLoop::runInLoop这个函数, 判断如果当前线程是不是 IO 线程, 如果是就直接执行任务, 不是就添加进任务队列, 并唤醒 IO 线程, 让他执行任务 因为在唤醒 IO 线程时, 用到了 eventfd, 先介绍一下 eventfd eventfd 的使用 eventfd 是linux 2.6.22后系统提供的一个轻量级的进程间通信的系统 继续阅读 >>


吕子健 18/12/12 21:29:38
文章目录muduo 的 Reactor 模式大概逻辑EventLoop classEventLoop.hEventLoop::loopChannel classChannel.hChannel.ccEpollPoller classPoller class初始化EpollPoller.hEpollPoller.cc 日后的学习中必然会有新的认识, 保持更新系列 muduo 的 Reactor 模式 muduo 中构成 reactor 模式的最核心的三个类是 Channel class, EpollPoller class, EventLoop class, 这三个类负责将 IO 复用拿到的各个类型的事件分发给各个文件描述符对应的事件处理函数 本文假设是在默认使用 epoll 的情况下分析的 大概逻辑 首先调用 EventLoop::loop 函数, 该函数循环调用 EpollPoller::poll 函数, 在poll 函数中会调用epoll_wait函数, 然后EventLoop::lo 继续阅读 >>


吕子健 18/12/12 11:24:53
文章目录什么是窗口窗口的目的滑动窗口发送窗口示意图ACK 里的重要信息如何滑动窗口大小和缓冲区的关系 什么是窗口 窗口是包含在 TCP 头里的一个16位的字段 窗口是一个已被发送方注入但还没有完成确认 (比如, 发送方已经发送, 却还没有收到 ACK) 的分组的集合, 窗口大小就是这个分组的数量. 滑动窗口在发送方和接收方又分为接收窗口和发送窗口 发送窗口记录了哪些分组可以被释放, 哪些分组正在等待 ACK. 和哪些分组还不能在排队等待发送 接收窗口记录着哪些分组已经被接收和确认, 哪些分组是是接下来期望收到的 (和分配多少内存来保存他们), 以及哪些分组即使被接受也会因为内存的限制而被抛弃 窗口的目的 我们知道数据的传输建立在网络层之上, 但是网络层是不可靠的, 他不关心数据是否已经正确到达对端, 上一篇说过 TCP 是建立在不可靠传输上的可靠协议 所以 TCP 要解决 : 数据包的丢失 数据包没有按顺序到达对端 (接收方收到的是乱序的) 网络实际的传输带宽和两端处理数据速度的不理想而导致可能出 继续阅读 >>


吕子健 18/11/29 23:22:55