笔记

Reactor

Reactor 要求主线程或内核负责监听文件描述符是否有事件发生,有的话立刻告知线程.数据读写全部由控制线程负责.同步io

epoll就是这种方式

组件

  1. event demultiplexer事件多路分发器,如select,poll,epoll
  2. handle事件源:用于识别每一个事件,Linux上是文件描述符
  3. Reactor反应器,用于管理事件的调度和注册删除
  4. event handler事件处理器:管理已经注册的事件和已经激活等待调度的事件,并分成了不同类型的事件(如读/写、信号),当事件发生时,会提供对应的处理程序。由Reactor调用。

Proactor

Proactor 所有io操作由主线程或者内核负责,控制线程只负责业务逻辑,异步io

aio

timewait

  • TCP四次挥手中,主动方在发送第二个ACK后的2MSL(max segment lifetime)时间之内,RFC推荐是2MSL=120,Linux内核2MSL=60s

  • 目的:防止ACK包丢失,等待是否有被动方重发的seq

  • 解决方法:

    • 编程时使用SO_REUSEADDR
    • Linux里
    1
    2
    3
    4
    5
    6
    7
    8
    # 启动TCP ts,tcp_tw_reuse和.tcp_tw_recycle依赖此实现
    net.ipv4.tcp_timestamps=1
    # 复用TIME_WAIT的socket
    net.ipv4.tcp_tw_reuse=1
    # 销毁TIME_WAIT的socket,由于nat可能会导致无法握手
    net.ipv4.tcp_tw_recycle=1
    # 重设超时
    net.ipv4.tcp_fin_timeout=30

Linux IO模型

  • 阻塞IO
  • 非阻塞IO
  • IO复用
  • 信号驱动IO
  • 异步IO

僵尸进程解决

  1. 两次fork.父进程创建子进程,子进程负责fork孙子进程,孙子进程负责执行逻辑业务,子进程fork完孙子线程后直接exit.孙子进程变成孤儿线程,交由init管理

  2. 子进程在结束时会向父线程发送SIGCHLD.父进程只要在信号处理函数中wait,进行子进程的PCB进行回收

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static void sig_child(int signo) {
    pid_t pid;
    int stat;
    //处理僵尸进程
    while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
    printf("child %d terminated.\n", pid);
    }
    int main() {
    signal(SIGCHLD, sig_child);
    ......
    }
  3. 忽略请求

    1
    signal(SIGCLD, SIG_IGN);

一致性hash

哈希值映射到圆环,节点分布在环上,顺时针的第一个节点就是数据存取节点

RVO (return value optimization) 和NRVO (named return value optimization)

Traits

被其他object或algorithm使用的,用来携带信息的object

实现:模板的特化与偏特化