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;
}

 

posted @ 2017-02-13 14:34  tomren  阅读(127)  评论(0编辑  收藏  举报