日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【项目介绍】协程——C语言实现的用户态非抢占式轻量级线程

發布時間:2024/4/11 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【项目介绍】协程——C语言实现的用户态非抢占式轻量级线程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 項目介紹
    • 開發語言
    • 開發環境
    • 項目簡介
    • 項目特點
    • 適用場景
    • 發布鏈接
  • 使用介紹
    • 上下文環境
    • 協程狀態
    • 協程與調度器結構體
    • 接口
  • 示范用例
    • 使用協程實現一個TCP服務器

項目介紹

開發語言

C


開發環境

CentOS7、vim、gcc、gdb、git、MakeFile


項目簡介

“協程”即用戶態下的非搶占式的輕量級線程,是一種在程序開發中處理多任務的組件。
由于在C/C++中并沒有引入協程這一概念,而大部分開源的庫又過于重量,所以我基于ucontext組件實現了一個簡單的協程庫


項目特點

  • 用戶態實現協程的調度切換,減少了內核切換的開銷。
  • 非搶占式,用戶自己實現調度,同一時間只能有一個協程在執行,由協程主動交出控制權。
  • 基于非對稱(asymmetric)模式, 控制流更加簡單,程序更加結構化。
  • 協程具有獨立的棧,確保運行效率。

適用場景

協程主要適用于I/O密集型的場景,如示例中的TCP服務器。在傳統的多路復用+多線程/多進程的做法,每并發一個進程/線程就會消耗內存,并且最嚴重的問題就是由系統來進行調度切換帶來的嚴重損耗,而協程剛好能夠解決這些問題。


發布鏈接

具體的實現請參考源代碼
協程


使用介紹

上下文環境

對于上下文環境的切換可以使用很多方法

  • 匯編
  • C語言庫函數setjmp, longjmp
  • glibc的ucontext組

我在這里使用的是ucontext組件,如果不了解這個組件的使用方法,可以參考我的另一篇博客
ucontext族函數的使用及原理分析

由于ucontext只支持posix,如果需要移植到windows,只需要將api換成fiber的即可


#define STACK_SIZE (1024 * 1024) //協程函數棧大小 #define COROUTINE_SIZE (1024) //協程最大數量

協程狀態

協程共設置了四種狀態,READY, RUNNING, DEAD, SUSPEND。下圖描述了所有狀態即狀態之間的轉換關系。


協程與調度器結構體

typedef struct coroutine {void* (*call_back)(struct schedule* s, void* args); //回調函數void* args; //回調函數的參數ucontext_t ctx; //協程的上下文char stack[STACK_SIZE]; //協程的函數棧enum State state; //協程狀態}coroutine;typedef struct schedule {coroutine** coroutines; //協程數組int cur_id; //正在運行的協程下標int max_id; //數組中最大的下標ucontext_t main; //主流程上下文 }schedule;

接口

//創建協程序調度器 schedule* schedule_create();//創建協程, 并返回協程所處下標 int coroutine_create(schedule* s, void* (*call_back)(schedule*, void* ), void* args);//協程讓出CPU,返回主流程上下文 void coroutine_yield(schedule* s);//恢復協程上下文 void coroutine_resume(schedule* s, int id);//運行協程 void coroutine_running(schedule* s, int id);//銷毀協程調度器 void schedule_destroy(schedule* s);//判斷協程調度器中的協程是否全部結束, 結束返回1, 沒結束返回0 int schedule_finished(schedule* s);

示范用例

使用協程實現一個TCP服務器

思路圖

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <fcntl.h>#include "coroutine.h" static int co_ids[COROUTINE_SIZE];void SetNoBlock(int fd) {int flag = fcntl(fd, F_GETFL, 0);flag |= O_NONBLOCK;fcntl(fd, F_SETFL, flag); }int socket_init() {int lst_fd = socket(AF_INET, SOCK_STREAM, 0);if(lst_fd == -1){perror("socket.\n");exit(1);}int op = 1;setsockopt(lst_fd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op));struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9200);addr.sin_addr.s_addr = inet_addr("192.168.0.128");if(bind(lst_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0){perror("bind.\n");exit(1);}if(listen(lst_fd, SOMAXCONN) < 0){ perror("listen.\n");exit(1);}return lst_fd; }void accept_conn(int lst_fd, schedule *s, int* co_ids, void *(*call_back)(schedule *s, void *args)) {while(1){int new_fd = accept(lst_fd, NULL, NULL);//如果有新連接到來則創建一個協程來管理這個連接if(new_fd > 0){SetNoBlock(new_fd);int args[] = {lst_fd, new_fd};int cid = coroutine_create(s, call_back, args);if(cid >= COROUTINE_SIZE){perror("too many connections.\n");return;}co_ids[cid] = 1;coroutine_running(s, cid);}//如果當前沒有連接,則切換至協程上下文中繼續運行else{int i = 0;for(i = 0; i < COROUTINE_SIZE; i++){if(co_ids[i] == -1){continue;}coroutine_resume(s, i);}}}}void *handle(schedule *s, void *args) {int* arr = (int*)args;int cfd = arr[1];char buf[1024] = { 0 };while(1){memset(buf, 0, sizeof(buf));int ret = recv(cfd, buf, 1024, 0);if(ret < 0){//如果此時沒有數據,則不再等待,直接切換回主流程coroutine_yield(s);}else if(ret == 0){//通信結束co_ids[s->cur_id] = -1;break;}else{printf("=> : %s\n", buf);if(strncasecmp(buf, "exit", 4) == 0){co_ids[s->cur_id] = -1;break;}send(cfd, buf, ret, 0);}} }int main() {static int co_ids[COROUTINE_SIZE];int lst_fd = socket_init();SetNoBlock(lst_fd);schedule* s = schedule_create();int i;for(i = 0; i < COROUTINE_SIZE; i++){co_ids[i] = -1;}accept_conn(lst_fd, s, co_ids, handle);schedule_destroy(s); }

可以看到該服務器可以快速的響應多個連接

總結

以上是生活随笔為你收集整理的【项目介绍】协程——C语言实现的用户态非抢占式轻量级线程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。