關於 coroutine , setjmp , longjmp implement 執行速度 比 ucontext 要來的快 ,
以下是 1024cores 強者 , 來自戰鬥民族的蘇聯人,寫了一篇關於 setjmp and longjmp的文章 :
http://www.1024cores.net/home/lock-free-algorithms/tricks/fibers
以及他用到 setjmp , longjmp 的工具 :
http://www.1024cores.net/home/relacy-race-detector
從這工具 source code , 我寫了 一支小小的測試程式 , 先簡單寫一下 ,
難一點的應用 後面再來寫 ~~~
1. marscoro.hpp
#ifndef TRANS_H
#define TRANS_H
#include <ucontext.h>
#include <memory.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <setjmp.h>
struct fiber_t
{
ucontext_t fib;
jmp_buf jmp;
};
struct fiber_ctx_t
{
void(* fnc)(void*);
void* ctx;
jmp_buf* cur;
ucontext_t* prv;
};
static void fiber_start_fnc(void* p)
{
struct fiber_ctx_t* ctx = (struct fiber_ctx_t*)p;
void (*volatile ufnc)(void*) = ctx->fnc;
void* volatile uctx = ctx->ctx;
if (_setjmp(*ctx->cur) == 0)
{
ucontext_t tmp;
swapcontext(&tmp, ctx->prv);
}
ufnc(uctx);
}
inline void create_main_fiber(fiber_t& fib)
{
memset(&fib, 0, sizeof(fib));
}
inline void delete_main_fiber(fiber_t& fib)
{
(void)fib;
}
inline void create_fiber(fiber_t& fib, void(*ufnc)(void*), void* uctx)
{
size_t const stack_size = 64*1024;
getcontext(&fib.fib);
fib.fib.uc_stack.ss_sp = (::malloc)(stack_size);
fib.fib.uc_stack.ss_size = stack_size;
fib.fib.uc_link = 0;
ucontext_t tmp;
struct fiber_ctx_t ctx = {ufnc, uctx, &fib.jmp, &tmp};
makecontext(&fib.fib, (void(*)())fiber_start_fnc, 1, &ctx);
swapcontext(&tmp, &fib.fib);
}
inline void delete_fiber(fiber_t& fib)
{
//(::free)(fib.uc_stack.ss_sp);
}
inline void switch_to_fiber(fiber_t& fib, fiber_t& prv)
{
if (_setjmp(prv.jmp) == 0)
_longjmp(fib.jmp, 1);
}
#endif
2. marscoro.cpp
#include <ucontext.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "marscoro.hpp"
struct fiber_t main_fiber_ ;
struct fiber_t fib1 ;
struct fiber_t fib2 ;
void testfunc1(void* x)
{
printf("testfunc1 \n") ;
while(1)
{
printf("hello1 \n") ;
switch_to_fiber(fib2,fib1);
sleep(1) ;
}
}
void testfunc2(void* x)
{
int icnt = 0 ;
printf("testfunc2 \n") ;
while(1)
{
printf("hello2 \n") ;
++icnt ;
if(icnt > 5)
switch_to_fiber(main_fiber_,fib2);
else
switch_to_fiber(fib1,fib2);
sleep(1) ;
}
}
typedef void (*fnx)(void*) ;
int main()
{
create_main_fiber(main_fiber_);
fnx f1 = &testfunc1 ;
int i1 = 0 ;
create_fiber(fib1,f1,(void*)(intptr_t)i1);
fnx f2 = &testfunc2 ;
int i2 = 1 ;
create_fiber(fib2,f2,(void*)(intptr_t)i2);
switch_to_fiber(fib1,main_fiber_);
printf("going to end \n") ;
delete_main_fiber(main_fiber_) ;
}
g++ --std=c++0x marscoro.cpp -o marscoro.exe
output :
testfunc1
hello1
testfunc2
hello2
hello1
hello2
hello1
hello2
hello1
hello2
hello1
hello2
hello1
hello2
going to end
留言列表