博客
关于我
【网络通信 -- 直播】SRS -- 协程基础知识点总结(一)
阅读量:368 次
发布时间:2019-03-04

本文共 5290 字,大约阅读时间需要 17 分钟。

网络通信 -- 直播 SRS -- 协程基础知识点总结(一)

协程作为一种轻量级的并发模型,能够在同一线程内实现多任务并发。其核心目标是解决I/O操作的异步性问题,为开发者提供同时具有异步性能与同步代码逻辑的解决方案。以下将从协程的基本概念、NtyCo库的实现细节以及相关技术内容进行系统总结。

协程简介

协程是一种轻量级的线程替代方案,其核心特点是通过用户态切换实现并发,而不是通过系统调度。传统的I/O操作是同步的,会导致单线程模型在高并发场景下性能严重下滑。而协程通过异步I/O操作,能够在不影响主线程的情况下,合理利用CPU资源。

IO 同步操作的逻辑代码

以下是协程中IO同步操作的典型逻辑实现:

int read_file(int fd, char *buf, int len) {    int nread;    while ((nread = read(fd, buf, len)) != -1) {        // 处理读取的数据        sleep(1); // 模拟I/O延迟    }    return nread;}

IO 异步操作的逻辑代码

相比之下,协程中的IO异步操作通过将I/O事件加入 epoll等事件驱动模型,实现了非阻塞I/O:

int read_file(int fd, char *buf, int len) {    int nread;    while ((nread = read(fd, buf, len)) != -1) {        event_loop.add_event(fd, POLLOUT);        yield(); // 让出CPU    }    return nread;}

IO 异步操作与同步操作对比

特性 同步操作 异步操作
I/O 操作类型 阻塞I/O 非阻塞I/O
性能 单线程瓶颈明显 高效利用CPU资源
代码逻辑复杂度 较高 较低
调用方式 同步I/O 调用 异步I/O 调用

NtyCo 简介

NtyCo 是一个用于C/C++开发的协程库,旨在提供轻量级的协程实现。其主要目标是为用户提供异步I/O操作的支持,同时保持代码的同步风格。NtyCo 的核心功能包括协程的创建、调度以及与 POSIX 异步I/O API 的集成。

NtyCo 相关 API 简介

NtyCo 提供了丰富的API接口,主要包括以下几个方面:

  • 协程相关 API

    • int nty_coroutine_create(nty_coroutine **new_co, proc_coroutine func, void *arg);
      用于创建新的协程实例。
    • void nty_schedule_run(void);
      用于调度协程运行。
  • POSIX 异步封装 API

    • int nty_socket(int domain, int type, int protocol);
      创建 socket 实例。
    • int nty_accept(int fd, struct sockaddr *addr, socklen_t *len);
      接收连接请求。
    • ssize_t nty_recv(int fd, void *buf, size_t len, int flags);
      接收数据。
    • ssize_t nty_send(int fd, const void *buf, size_t len, int flags);
      发送数据。
    • int nty_close(int fd);
      关闭 socket 实例。
  • 协程的实现

  • 协程的实现之创建协程

    协程的创建过程包括以下几个步骤:

    • 调度器的创建与管理。
    • 协程内存的分配与初始化。
    • 协程的状态设置(就绪、睡眠等)。
    • 协程的添加到调度器的就绪队列中。
  • 协程的实现之实现 IO 异步操作

    在协程中实现IO异步操作的关键步骤包括:

    • 将 socket 描述符添加到 epoll 管理中。
    • 进行上下文切换,即让出CPU。
    • 调度器获取下一个协程上下文,恢复其运行。
  • 协程实现之回调协程的子过程

    static void nty_coroutine_init(nty_coroutine *co) {    void **stack = (void **)(co->stack + co->stack_size);    stack[-3] = NULL;    stack[-2] = (void *)co; // ctx 协程的上下文    co->ctx.esp = (void *)stack - (4 * sizeof(void *));    co->ctx.ebp = (void *)stack - (3 * sizeof(void *));    co->ctx.eip = (void *)_exec;    co->status = BIT(NTY_COROUTINE_STATUS_READY);}
    static void _exec(void *lt) {    nty_coroutine *co = (nty_coroutine *)lt;    co->func(co->arg);    // 设置协程状态    co->status |= (BIT(NTY_COROUTINE_STATUS_EXITED) |                  BIT(NTY_COROUTINE_STATUS_FDEOF) |                  BIT(NTY_COROUTINE_STATUS_DETACH));    if (1) {        nty_coroutine_yield(co);    } else {        switch(&co->sched->ctx, &co->ctx);    }}
    1. 协程实现之原语操作
      协程的核心原语操作包括 createyield,其中 exit 的实现通过子过程的返回自动完成。
    2. 协程实现之切换

      上下文切换是协程实现的关键步骤,主要包括 CPU 寄存器的保存与恢复。NtyCo 中定义了 nty_cpu_ctx 结构体来管理上下文切换:

      typedef struct _nty_cpu_ctx {    void *esp;    void *ebp;    void *eip;    void *edi;    void *esi;    void *ebx;    void *r1;    void *r2;    void *r3;    void *r4;    void *r5;} nty_cpu_ctx;

      切换过程通过 _switch 函数实现:

      int _switch(nty_cpu_ctx *new_ctx, nty_cpu_ctx *cur_ctx) {    movq %rsp, 0(*new_ctx);    movq %rbp, 8(*new_ctx);    movq %rax, 16(*new_ctx);    movq %rbx, 24(*new_ctx);    movq %r12, 32(*new_ctx);    movq %r13, 40(*new_ctx);    movq %r14, 48(*new_ctx);    movq %r15, 56(*new_ctx);    movq 56(*new_ctx), %r15;    movq 48(*new_ctx), %r14;    movq 40(*new_ctx), %r13;    movq 32(*new_ctx), %r12;    movq 24(*new_ctx), %rbx;    movq 16(*new_ctx), %rax;    movq %rax, 0(*cur_ctx);    ret;}

      协程实现之调度器

      调度器是协程运行的核心管理器,其主要功能是根据事件驱动模型,将就绪的协程恢复运行。NtyCo 的调度器主要采用生产者消费者模式,通过 epoll 实现高效的事件处理。

      生产者消费者模式

      调度器的实现逻辑如下:

      while (1) {    // 处理睡眠集合中的协程    nty_coroutine *expired = NULL;    while ((expired = sleep_tree_expired(sched)) != NULL) {        TAILQ_ADD(&sched->ready, expired);    }    // 处理等待集合中的协程    nty_coroutine *wait = NULL;    int nready = epoll_wait(sched->epfd, events, EVENT_MAX, 1);    for (i = 0; i < nready; i++) {        wait = wait_tree_search(events[i].data.fd);        TAILQ_ADD(&sched->ready, wait);    }    // 恢复 ready 队列中的协程    while (!TAILQ_EMPTY(sched->ready)) {        nty_coroutine *ready = TAILQ_POP(sched->ready);        resume(ready);    }}

      多状态运行

      调度器的实现也支持多状态运行模式:

      while (1) {    // 处理睡眠集合中的协程    nty_coroutine *expired = NULL;    while ((expired = sleep_tree_expired(sched)) != NULL) {        resume(expired);    }    // 处理等待集合中的协程    nty_coroutine *wait = NULL;    int nready = epoll_wait(sched->epfd, events, EVENT_MAX, 1);    for (i = 0; i < nready; i++) {        wait = wait_tree_search(events[i].data.fd);        resume(wait);    }    // 恢复 ready 队列中的协程    while (!TAILQ_EMPTY(sched->ready)) {        nty_coroutine *ready = TAILQ_POP(sched->ready);        resume(ready);    }}

      寄存器与栈帧

      寄存器

      X86-64 处理器支持 16 个通用寄存器(%rax, %rbx, %rcx, %rdx, %rsi, %rdi, %rbp, %rsp, %r8, %r9, %r10, %r11, %r12, %r13, %r14, %r15)。这些寄存器的使用遵循特定的存储惯例:

    3. 通用寄存器

      • %rax, %rbx, %rcx, %rdx, %rsi, %rdi, %rbp, %rsp 用于数据存储。
      • %rbp, %rsp 用于函数调用时的上下文保存。
      • %r10, %r11 用于调用者使用的寄存器。
    4. 段寄存器

      • cs, ds, es, fs, gs, ss 用于段控制。
    5. 状态和控制寄存器 eflags

      eflags 包含多个状态位和控制位,如 CF, PF, AF, ZF, SF, OF, TF, IF, DF。

    6. 指令寄存器 EIP/RIP

      用于存储当前进程将要执行的指令位置。

    7. 栈帧

      栈帧是函数调用和返回的基础机制。每个栈帧包括:

      • 寄存器上下文保存(如 %rbp, %rsp)。
      • 函数返回地址(通过 %rip 存储)。
      • 函数参数和局部变量存储。

      以下是 sfact 函数的汇编代码分析:

      ; 1. 函数参数传递foo(0, 1, 2, 3, 4, 5, 6)pushl %ripjmp foo; 2. 函数返回popl %ripret; 3. 字乘法实现lea 16(%%rdi), %%r8imul %%r8, %%rdxpopl %%r8

      结构体传递

      结构体传递需要注意以下几点:

    8. 结构体如何分解:通过偏移量和基地址。
    9. 结构体如何存储:使用指针或数组方式。
    10. 结构体如何返回:使用寄存器或栈存储。
    11. 通过以上内容可以看出,协程技术在网络通信中的应用具有重要意义。NtyCo 库通过高效的调度器实现了多任务并发,同时提供了灵活的I/O操作接口。理解这些实现细节对于开发高性能网络应用具有重要的理论基础和实践意义。

    转载地址:http://olmr.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现n body simulationn体模拟算法(附完整源码)
    查看>>
    Objective-C实现naive string search字符串搜索算法(附完整源码)
    查看>>
    Objective-C实现natural sort自然排序算法(附完整源码)
    查看>>
    Objective-C实现nested brackets嵌套括号算法(附完整源码)
    查看>>
    Objective-C实现nevilles method多项式插值算法(附完整源码)
    查看>>
    Objective-C实现newton raphson牛顿-拉夫森算法(附完整源码)
    查看>>
    Objective-C实现newtons second law of motion牛顿第二运动定律算法(附完整源码)
    查看>>
    Objective-C实现newton_forward_interpolation牛顿前插算法(附完整源码)
    查看>>
    Objective-C实现newton_raphson牛顿拉夫森算法(附完整源码)
    查看>>
    Objective-C实现ngram语言模型算法(附完整源码)
    查看>>
    Objective-C实现NLP中文分词(附完整源码)
    查看>>
    Objective-C实现NLP中文分词(附完整源码)
    查看>>
    Objective-C实现NMS非极大值抑制(附完整源码)
    查看>>
    Objective-C实现NMS非极大值抑制(附完整源码)
    查看>>
    Objective-C实现Node.Js中生成一个UUID/GUID算法(附完整源码)
    查看>>
    Objective-C实现not gate非门算法(附完整源码)
    查看>>
    Objective-C实现NQueen皇后问题算法(附完整源码)
    查看>>
    Objective-C实现number of digits解字符数算法(附完整源码)
    查看>>
    Objective-C实现NumberOfIslands岛屿的个数算法(附完整源码)
    查看>>
    Objective-C实现numerical integration数值积分算法(附完整源码)
    查看>>