基于windows fiber的协程(coroutine)实现

2021-06-29 19:07

阅读:469

标签:expr   push   cout   rda   _MSC_VER   air   ack   called   函数   

一个非常简单,但是实用的协程实现,使用Windows的*Fiber函数族(linux可以稍微改一下用*context函数族)。

fco.h

#ifndef _MSC_VER
#error "this fast coroutine library only supports MSVC building chain"
#endif

#include 
#include 
#include 

namespace fco {
static constexpr int ERR_NOT_EXIST_CO = -1;

enum Status {
  READY,  // Set up to READY when fco::newco() called
  AWAIT,  // Set up to AWAIT when fco::yield() called
};

struct Scheduler;
struct Coroutine;

struct Coroutine {
  void (*task)(Scheduler*, void*);
  void* userData;
  char status;
  LPVOID winFiber;
};

struct Scheduler {
  std::map coroutines;
  int currentIdx;
  LPVOID main;
};

void __stdcall __entry(LPVOID lpParameter);

Scheduler* initialize();

void destroy(Scheduler* s);

int newco(Scheduler* scheduler, void (*task)(Scheduler*, void*),
          void* userData);

void resume(Scheduler* s, int coid);

void yield(Scheduler* scheduler);

int current(Scheduler* scheduler);

}  // namespace fco

fco.cpp

#include "fco.h"

// Initialize fco library, return a global scheduler
fco::Scheduler* fco::initialize() {
  Scheduler* sched = new Scheduler;
  sched->currentIdx = ERR_NOT_EXIST_CO;
  sched->main = ConvertThreadToFiber(NULL);
  return sched;
}

// Release all resources
void fco::destroy(Scheduler* s) {
  for (auto& c : s->coroutines) {
    DeleteFiber(c.second->winFiber);
  }
  delete s;
}

// This is should NEVER BE called on user land
void __stdcall fco::__entry(LPVOID lpParameter) {
  // Execute the task of current coroutine
  Scheduler* s = (Scheduler*)lpParameter;
  Coroutine* currentCo = s->coroutines[s->currentIdx];
  (currentCo->task)(s, currentCo->userData);

  // Clean up executed task
  s->coroutines.erase(s->coroutines.find(s->currentIdx));
  s->currentIdx = ERR_NOT_EXIST_CO;
  currentCo->status = Status::READY;
  DeleteFiber(currentCo->winFiber);
  delete currentCo;

  // Switch to entry function
  SwitchToFiber(s->main);
}

// Create new coroutine and return an unique identity
int fco::newco(Scheduler* scheduler, void (*task)(fco::Scheduler*, void*),
               void* userData) {
  Coroutine* co = new Coroutine;
  co->task = task;
  co->userData = userData;
  co->winFiber = CreateFiber(0, __entry, scheduler);
  if (co->winFiber == NULL) {
    return ERR_NOT_EXIST_CO;
  }
  co->status = Status::READY;
  int newCoId =
      scheduler->coroutines.size() != 0
          ? scheduler->coroutines.end().operator--().operator*().first + 1
          : 0;
  scheduler->coroutines.insert(std::make_pair(newCoId, co));
  return newCoId;
}

// Resume suspended coroutine by given coid
void fco::resume(fco::Scheduler* scheduler, int coid) {
  if (coid coroutines[coid];
  if (co->status == Status::READY || co->status == Status::AWAIT) {
    scheduler->currentIdx = coid;
    scheduler->coroutines[scheduler->currentIdx]->status = Status::AWAIT;
    co->status = Status::READY;
    SwitchToFiber(co->winFiber);
  }
}

// Yield CPU time to main coroutine
void fco::yield(fco::Scheduler* scheduler) {
  Coroutine* co = scheduler->coroutines[scheduler->currentIdx];
  co->status = Status::AWAIT;

  scheduler->currentIdx = ERR_NOT_EXIST_CO;
  SwitchToFiber(scheduler->main);
}

// Get current running coroutine identity
int fco::current(Scheduler* scheduler) { return scheduler->currentIdx; }

example

  • hello world
#include 
#include 
#include 
#include 
#include "fco.h"

void bar(fco::Scheduler* s, void* param) {
  for (int i = 0; i 
  • 生产者消费者模型
#include 
#include 
#include 
#include 
#include "fco.h"

std::vector vec;

void producer(fco::Scheduler* s, void* param) {
  while (vec.size() 

基于windows fiber的协程(coroutine)实现

标签:expr   push   cout   rda   _MSC_VER   air   ack   called   函数   

原文地址:https://www.cnblogs.com/racaljk/p/10010106.html

上一篇:Qt窗体圆角

下一篇:RestfulAPI超简单入门


评论


亲,登录后才可以留言!