首页 > 其他分享 >协程

协程

时间:2023-07-06 12:35:57浏览次数:47  
标签:co cur coroutine next coroutines 协程 struct

#include "co.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


enum state{
  CREATED  = 0,
  RUNNING,
  HALT,
  WAIT,
  FINISHED
};

#define STACK_SIZE 4 * 1024 * 1024 * sizeof(char)

struct co {
  char         stack[STACK_SIZE];
  const char*  name;
  void*        arg;
  enum state   s;
  jmp_buf      context;
  uint64_t     RIP;
  uint64_t     RBP;
  uint64_t     RSP;
  struct co*   wait;
  //当前协程被谁等
  struct co*   waited;
};


struct{
  // coroutine[0] 始终存储main函数的stack frame
  struct co* coroutine[100];
  int        count;
  int        cur_idx;
  int        cnt;
  uint64_t   yield_func;
}coroutines;

struct co *co_start(const char *name, void (*func)(void *), void *arg) {
  // 如果是NULL,说明是首次调度,给main函数创建一个coroutine
  if(coroutines.coroutine[0] == NULL){
      coroutines.yield_func = (uint64_t)(void (*)())finish_co;

      struct co* coroutine = (struct co*) malloc(sizeof(struct co));
      coroutine->s = HALT;
      coroutines.coroutine[0] = coroutine;
      coroutines.cnt = 1;
  }

  ++coroutines.cnt;
  struct co* coroutine = (struct co*) malloc(sizeof(struct co));
  coroutine->name = name;
  coroutine->arg = arg;
  coroutine->s = CREATED;
  coroutine->RIP = (uint64_t)func;
  coroutine->RSP = (uint64_t)coroutine->stack + STACK_SIZE;
  coroutines.coroutine[++coroutines.count] = coroutine;
  return coroutine;
}

void co_wait(struct co *co) {
  if(co->s == FINISHED) return;
  struct co* cur = coroutines.coroutine[coroutines.cur_idx];
  
  co->waited = cur;
  cur->wait = co;

  cur->s = WAIT;
  co_yield();
}

void finish_co(){
  struct co *co = coroutines.coroutine[coroutines.cur_idx];
  co->s = FINISHED;
  --coroutines.cnt;
    
  if(co->waited != NULL){
    co->waited->wait = NULL;
    co->waited->s = HALT;
  }
  co_yield();
}

void change_thread(int next_idx){
  struct co* current = coroutines.coroutine[coroutines.cur_idx];
  struct co* next = coroutines.coroutine[next_idx];
  coroutines.cur_idx = next_idx;

  if(current->s == RUNNING) current->s = HALT;
  int flag = next->s;
  next->s = RUNNING;
  
  if(flag == CREATED){
    asm volatile(
        "movq    %0, %%rsp\n\t"
        "pushq   %3\n\t"
        "movq    %1, %%rdi\n\t"
        "jmp     *%2\n\t"
      :
      : "m"(next->RSP),
        "m"(next->arg),
        "m"(next->RIP),
        "m"(coroutines.yield_func)
      );
  } else {
    longjmp(next->context, 1);
  }
}

void co_yield() {
  if(!coroutines.cnt) return;
  int nxt = coroutines.cur_idx;
  struct co* cur_co = coroutines.coroutine[nxt];
  
  if(!setjmp(cur_co->context))
  {
    // jump to other program
    for(nxt = (nxt+1) % (coroutines.count + 1); 
        nxt <= coroutines.count;
        nxt=(nxt+1)%(coroutines.count+1))
    {
      if(coroutines.coroutine[nxt]->s == HALT 
          || coroutines.coroutine[nxt]->s == CREATED)
      {
        change_thread(nxt);
        break;
      }
    }
  }
}

标签:co,cur,coroutine,next,coroutines,协程,struct
From: https://www.cnblogs.com/INnoVationv2/p/17531836.html

相关文章

  • aiohttp模块引出_aiohttp+多任务异步协程实现异步爬虫
    1.为什么要用aiohttp模块引出: 2.异步模块aiohttp对比requests基于同步的区别: 3.需要在response.text()前面添加await进行手动挂起: 4.response.text()前面一定要添加await再次运行程序告警取消: 5.异步爬虫get或post中写入的参数: ......
  • unity协程(IEnumerator)开始和结束
    仅用于记录遇到的问题和解决方案。快速阅览:一、结束协程无效:协程方法需要单独存一份privateIEnumeratormyTest,再开始和结束不直接传入方法名,而是使用这份保存的myTest进行开始和结束。二、再次开启协程时少跑了几行代码:再次开始同一个方法名的协程时,不是从第一句代码开始执行......
  • 多任务异步协程实现
    1.未实现异步操作代码: 2.实现异步操作代码: ......
  • AI智慧安监EasyCVR平台长时间运行出现协程高的现象是什么原因?
    EasyCVR视频融合平台基于云边端协同架构,具有强大的数据接入、处理及分发能力,平台支持海量视频汇聚管理,可支持多协议接入,包括市场主流标准协议与厂家私有协议及SDK,如:国标GB28181、RTMP、RTSP/Onvif、海康Ehome、海康SDK、大华SDK、宇视SDK等。有用户反馈,EasyCVR平台向上级联后,运......
  • 谈一谈进程、线程与协程
    进程、线程、协程概念什么是进程进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。在Java中,当启动main方法时其实就是启动了一个JVM的进程,而main方法所在的线程就是这个进程中的一个线程,称为主......
  • 协程
    可以暂停和恢复的函数             await_resume返回的值就是co_wait的值 ......
  • go:接口、并发与协程、信道、缓冲信道、mutex、异常处理
    目录接口并发与协程信道、缓冲信道mutex异常处理接口1.实现多个接口2.接口嵌套3.接口零值packagemainimport"fmt"//接口//1实现多个接口具体类型可以赋值给多种接口类型//typeAnimalinterface{// run()//}////typeDoginterface{// eat()//}///......
  • 【5.0】知识点小结(协程进阶)
    【5.0】知识点小结(协程进阶)【一】IO模型简介我们研究的IO都是基于网络IO的Stevens在文章中一共比较了五种IOModel:blockingIOnonblockingIOIOmultiplexingsignaldrivenIO---(忽略)asynchronousIO由signaldrivenIO(信号驱动IO)在实际中并不常用,所以主要介绍......
  • 多进程和多线程以及协程的创建模板
    【一】开启多进程的创建模板(基于Process模块)【1】方式一:创建多进程importmultiprocessingdefworker(n):"""子进程要执行的任务"""print(f'子进程{n}正在执行')defmain():task_lists=[]foriinrange(100)#创建一个进程对象......
  • golang 常用控制协程的三种方式
    waitGroupwaitGroup这种方式适用于一个任务可以被拆分成几个子任务,并且子任务之间的关联程度不高,全部的子任务都完成,才会进行下一阶段的任务。packagemainimport( "fmt" "sync" "time")funcmain(){ varwgsync.WaitGroup wg.Add(3) gofunc(){ deferwg.Do......