C 协程练习
协程干货
http://blog.csdn.net/qq910894904/article/details/41911175
#include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <stdint.h> #include <ucontext.h> #include <unistd.h> #include <map> #include <sys/time.h> #define STACK_SIZE 1024 #define INVALID_ID -1 // -------------------------------------------------- #define COROUTINE_DEAD 0 #define COROUTINE_READY 1 #define COROUTINE_RUNNING 2 #define COROUTINE_SUSPEND 3 int gco_id = 0; typedef void (*co_func)(uint32_t, uint32_t); typedef struct co_struct { int id; int status; ucontext_t ctx; co_func func; void* arg; char stack[STACK_SIZE]; }co_struct; typedef struct co_schedule { ucontext_t main; int running; std::map<int, co_struct*> coroutine; }co_schedule; co_struct* get_co(co_schedule* sc, int co_id) { if(NULL == sc) return NULL; std::map<int, co_struct*>::iterator it = sc->coroutine.find(co_id); if(it == sc->coroutine.end()) return NULL; return it->second; } int co_create(co_schedule* schedule, co_func func, void* arg) { if(NULL == schedule) return false; co_struct* co = (co_struct*)malloc(sizeof(co_struct)); if(NULL == co) return INVALID_ID; co->id = ++gco_id; co->status = COROUTINE_READY; co->func = func; co->arg = arg; schedule->coroutine[co->id] = co; return co->id; } void co_yield(co_schedule* sc) { co_struct* co = get_co(sc, sc->running); if(NULL == co) return; co->status = COROUTINE_SUSPEND; sc->running = INVALID_ID; swapcontext(&co->ctx, &sc->main); } void child_func(uint32_t lp, uint32_t hp) { co_schedule* sc = (co_schedule*)((uintptr_t)lp | ((uintptr_t)hp << 32)); //printf("%lu\n", sizeof(uintptr_t)) //printf("-----\n"); //printf("%u\n", lp); //printf("%u\n", hp); //printf("%lu\n", sc); while(1) { printf("child_func %d\n", sc->running); printf("child_func %d, %d\n", sc->running, sc->running); fflush(stdout); sleep(1); co_yield(sc); //printf("child_func %d, %d, %d\n", sc->running, sc->running, sc->running); //printf("child_func %d, %d, %d, %d\n", sc->running, sc->running, sc->running, sc->running); //fflush(stdout); } co_struct* co = get_co(sc, sc->running); if (NULL != co) { co->status = COROUTINE_DEAD; } } bool co_resume(co_schedule* sc, int co_id) { co_struct* co = get_co(sc, co_id); if(NULL == co) return false; switch(co->status) { case COROUTINE_READY: { getcontext(&co->ctx); co->ctx.uc_stack.ss_sp = co->stack; co->ctx.uc_stack.ss_size = STACK_SIZE; co->ctx.uc_stack.ss_flags = 0; co->ctx.uc_link = &sc->main; uintptr_t lp = (uintptr_t)sc; uintptr_t hp = (uintptr_t)sc >> 32; printf(".....\n"); printf("%u\n", lp); printf("+++++\n"); printf("%u\n", hp); fflush(stdout); makecontext(&co->ctx,(void (*)())(child_func), 2, (uintptr_t)sc, (uintptr_t)sc >> 32); sc->running = co->id; co->status = COROUTINE_RUNNING; swapcontext(&sc->main, &co->ctx); } break; case COROUTINE_SUSPEND: { co->status = COROUTINE_RUNNING; sc->running = co->id; swapcontext(&sc->main, &co->ctx); } break; } return true; } void co_close(co_schedule* sc) { } bool is_co_live(co_schedule* sc, int co_id) { co_struct* co = get_co(sc, co_id); if(NULL == co) return false; if (co->status != COROUTINE_DEAD) return true; return false; } void test_coroutine() { char stack[1024 * 64]; ucontext_t context, main_context; getcontext(&context); context.uc_stack.ss_sp = stack; context.uc_stack.ss_size = sizeof(stack); context.uc_stack.ss_flags = 0; context.uc_link = &main_context; makecontext(&context, (void (*)(void))child_func, 2, 1, 2); swapcontext(&main_context, &context); printf("test_coroutine\n"); fflush(stdout); } static char msg[] = "time is running out/n"; void prompt_info(int signo) { //write(STDERR_FILENO, msg, len); puts(msg); puts("zzzZZZ"); } void init_sigaction() { struct sigaction tact; tact.sa_handler = prompt_info; tact.sa_flags = 0; sigemptyset(&tact.sa_mask); sigaction(SIGALRM, &tact, NULL); } void init_timer() { struct itimerval value; value.it_value.tv_sec = 3; value.it_value.tv_usec = 0; value.it_interval = value.it_value; setitimer(ITIMER_REAL, &value, NULL); } int main(int argc, char* argv[]) { //test_coroutine(); co_schedule sc; init_sigaction(); init_timer(); printf("%lu\n", &sc); int c1 = co_create(&sc, child_func, NULL); int c2 = co_create(&sc, child_func, NULL); while(is_co_live(&sc, c1) || is_co_live(&sc, c2)) { co_resume(&sc, c1); co_resume(&sc, c2); } printf("exit main\n"); fflush(stdout); return 0; }