当前位置: 首页 > 软件库 > 程序开发 > 协议和规范 >

servcraft/p7

Stackful协程库
授权协议 BSD
开发语言 C/C++
所属分类 程序开发、 协议和规范
软件类型 开源软件
地区 国产
投 递 者 戚修雅
操作系统 Linux
开源组织
适用人群 未知
 软件概览

servcraft/p7是使用C实现的stackful协程库,提供“半”透明的CSP并发。

目前,servcraft只支持Linux/GCC/pthread. 由于阻塞IO封装使用了epoll, 推荐使用Linux 2.6以上。

若要利用servcraft提供的GCC闭包功能,请使用主版本号不低于5的GCC.

servcraft/p7所使用的协程(coroutines, coro)提供类似goroutine的功能。

  • 编写并发程序的过程较一般事件驱动框架更简单。每个协程假定自己和其他协程一样,被并发地调度且独立地执行,因而可以顺序编写逻辑。

  • 为使用文件描述符的系统调用提供了IO阻塞-重调度接口。协程阻塞在IO操作上时自动暂停执行、引发重调度,IO就绪时重新获得调度权。

  • 提供Actor风格的协程间通信。协程可以注册自身名字,并按注册的协程名向其他协程的内建邮箱中(零拷贝地)投递信息。

  • 所有IO和协程间通信的阻塞接口都自带超时定时器。

  • 提供协程间瘦自旋锁和读写自旋锁。读写自旋锁使用尽量公平对待读者、写者的机制。

简介和简单demo可以在这里获得。一个粗暴的echo server如下:

#include    <stdio.h>
#include    "./net_common.h"        // common header for necessary network APIs
#include    <sys/stat.h>
#include    "../servcraft/p7/libp7.h"
#include    "../servcraft/p7/p7_root_alloc.h"
#include    "../servcraft/include/model_alloc.h"

void test_echo(void *arg) {
    intptr_t fd_conn_i64crap = (long long) arg;
    int fd_conn = (int) (fd_conn_i64crap & 0xFFFFFFFF);
    char msg[32];
    memset(msg, 0, sizeof(char) * 32);
    int ret = p7_iowrap_timed(recv, P7_IOMODE_READ, 30000, fd_conn, msg, sizeof(msg), 0);
    switch (ret) {
        case -1:
            printf("internal error\n");
            break;
        case -2:
            printf("p7 timed out\n");
            break;
        default:
            p7_iowrap(send, P7_IOMODE_WRITE, fd_conn, msg, strlen(msg), 0);
    }
    close(fd_conn);
}

void test_timeout(void *arg) {
    long long fd_conn_i64crap = (long long) arg;
    int fd_conn = (int) (fd_conn_i64crap & 0xFFFFFFFF);
    printf("Timed out: %d\n", fd_conn);
}

void test_echo_wrapper(void *arg) {
    p7_coro_concat(test_echo, arg, 2048);
}

void test_startup(void *unused) {
    printf("startup\n");
}

int main(int argc, char *argv[]) {
    __auto_type allocator = p7_root_alloc_get_allocator();
    allocator->allocator_.closure_ = malloc;
    allocator->deallocator_.closure_ = free;
    allocator->reallocator_.closure_ = realloc;

    struct p7_init_config config;
    config.namespace_config.namespace_size = 1024;
    config.namespace_config.rwlock_granularity = 10;
    config.namespace_config.spintime = 400;
    config.pthread_config.nthreads = atoi(argv[1]);
    config.pthread_config.at_startup = test_startup;
    config.pthread_config.arg_startup = NULL;
    p7_init(config);

    int fd_listen;

    if ((fd_listen = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    struct sockaddr_in lserv;
    lserv.sin_family = AF_INET;
    lserv.sin_port = htons(8080);
    lserv.sin_addr.s_addr = inet_addr(argv[2]);
    bzero(&(lserv.sin_zero), 8);

    if (bind(fd_listen, (struct sockaddr *) &lserv, sizeof(lserv)) == -1) {
        perror("bind");
        exit(1);
    }
    
    if (listen(fd_listen, 5) == -1) {
        perror("listen");
        exit(1);
    }

    while (1) {
        struct sockaddr_in rcli;
        socklen_t addrlen = sizeof(rcli);
        int fd_conn = p7_iowrap(accept, P7_IOMODE_READ, fd_listen, (struct sockaddr *) &rcli, &addrlen);
        intptr_t fd_conn_i64crap = fd_conn;
        p7_coro_create(test_echo_wrapper, (void *) fd_conn_i64crap, 512);
    }

    return 0;
}
 相关资料
  • 与子程序(或者说函数)一样,协程(coroutine)也是一种程序组件。Donald Knuth 曾说,子程序是协程的特例。 一个子程序就是一次函数调用,它只有一个入口,一次返回,调用顺序是明确的。但协程的调用和子程序则大不一样,协程允许有多个入口对程序进行中断、继续执行等操作。 Python2 可以通过 yield 来实现基本的协程,但不够强大,第三方库 gevent 对协程提供了强大的支持。另

  • Tornado 中推荐用 协程 来编写异步代码. 协程使用 Python 中的关键字 yield 来替代链式回调来实现挂起和继续程序的执行(像在 gevent 中使用的轻量级线程合作的方法有时也称作协程, 但是在 Tornado 中所有协程使用异步函数来实现的明确的上下文切换). 协程和异步编程的代码一样简单, 而且不用浪费额外的线程, . 它们还可以减少上下文切换 让并发更简单 . Exampl

  • defer 协程客户端的对象结构体,设置client->defer = 1表示启用了defer延迟收包 设置client->defer_yield = 1表示进入了wait状态 事件监听 因为swoole底层的EventLoop总是在运行的,因此可能某个协程客户端没有yield也会收到包。底层需要对数据进行缓存。 Client 自动保存到ccp->result内存中。为了避免收到的数据过多,导致内

  • 概念 Hyperf 是运行于 Swoole 4 的协程之上的,这也是 Hyperf 能提供高性能的其中一个很大的因素。 PHP-FPM 的运作模式 在聊协程是什么之前,我们先聊聊传统 PHP-FPM 架构的运作模式,PHP-FPM 是一个多进程的 FastCGI 管理程序,是绝大多数 PHP 应用所使用的运行模式。假设我们使用 Nginx 提供 HTTP 服务(Apache 同理),所有客户端发起

  • Python的协程很像生成器,但并不是生成数据,大多数时候扮演了数据消费者的作用。换句话说,协程是一个在每次使用send方法发送数据后就会被唤醒的函数。 协程的要点是将“yield”关键字写在表达式的右边。下面是一个打印出所发送的值的协程例子: def coroutine(): print('My coroutine') while True: val = yiel

  • 就一个简单实现的语言来说,如果有并发需求,像之前说的直接使用宿主环境的线程,加上必要的调度控制即可实现需求,但如果要求比较高,触发到上篇讲的线程和单线程异步的相关缺陷,一个较普遍的解决办法是采用用户态并发,即对于os内核来说,进程只有一个或少数几个线程,而对于源语言来说,接口和使用线程别无二致,由虚拟机实现对这些“线程”的调度,虚拟机的实现则可以一定程度简化、优化调度算法和内存占用,从而达到高并发