zoukankan      html  css  js  c++  java
  • ucontext实现的用户级多线程框架

    昨天看CN-Erlounge-IV讲搞的其中一篇<erlang进程模型在C++中的实践>,对用coroutine实现用户态的线程非常感兴趣,于是查下资料

    写了个简单的实验框架,其中schedule算法的实现很简单,只是遍历所有可以执行的coroutine.

    代码如下:

    uthread.h

    /*
    * brief: 用ucontext实现的用户级线程框架
    * author: kenny huang
    * date: 2009/10/13
    * email: huangweilook@21cn.com
    */
    #ifndef _UTHREAD_H
    #define _UTHREAD_H
    #include <ucontext.h>
    #include <stdio.h>
    #include <string.h>
    #include <list>
    #define MAX_UTHREAD 128
    typedef int uthread_id;
    #define INVAID_ID -1
    //用户态线程的当前状态
    enum thread_status
    {
    ACTIVED = 0,//可运行的
    BLOCKED,//被阻塞
    SLEEP,//主动休眠
    DIE,//死死亡
    };

    class runnable
    {
    public:
    virtual void main_routine() = 0;
    };
    class Scheduler;
    /*
    * 用户态线程
    */
    class u_thread
    {
    friend class Scheduler;
    private:
    u_thread(runnable *rable,unsigned int ssize,uthread_id uid)
    :ssize(ssize),_status(BLOCKED),rable(rable),uid(uid)
    {
    stack = new char[ssize];
    ucontext.uc_stack.ss_sp = stack;
    ucontext.uc_stack.ss_size = ssize;
    getcontext(&ucontext);
    }
    ~u_thread()
    {
    delete []stack;
    }
    static void star_routine();

    public:
    ucontext_t &GetContext()
    {
    return ucontext;
    }
    void SetStatus(thread_status _status)
    {
    this->_status = _status;
    }
    thread_status GetStatus()
    {
    return _status;
    }
    uthread_id GetUid()
    {
    return uid;
    }
    //休眠time时间
    static void sleep(uthread_id utid,int t);

    private:
    ucontext_t ucontext;
    char *stack;//coroutine使用的栈
    unsigned int ssize;//栈的大小
    thread_status _status;
    runnable *rable;
    uthread_id uid;
    };
    /*
    * 任务调度器
    */
    class Scheduler
    {
    //friend void u_thread::star_routine();
    friend class u_thread;
    public:
    static void scheduler_init();
    static void schedule();
    static uthread_id uthread_create(runnable *rable,unsigned int stacksize);
    private:
    static u_thread *GetCurrentUThread()
    {
    if(current == -1)
    return NULL;
    return threads[current];
    }
    //休眠time时间
    static void sleep(uthread_id utid,int t);
    private:
    static std::list<u_thread*> activeList;//可运行uthread列表

    static std::list<std::pair<u_thread*,time_t> > sleepList;//正在睡眠uthread列表

    static char stack[4096];

    static ucontext_t ucontext;

    static u_thread *threads[MAX_UTHREAD];
    static int total_count;
    static int current;//在uthread创建时使用的
    };

    #endif

    uthread.cpp

    #include "uthread.h"
    #include <assert.h>
    #include <stdlib.h>
    #include <time.h>
    ucontext_t Scheduler::ucontext;
    char Scheduler::stack[4096];
    u_thread *Scheduler::threads[128];
    int Scheduler::total_count = 0;
    int Scheduler::current = -1;
    std::list<u_thread*> Scheduler::activeList;
    std::list<std::pair<u_thread*,time_t> > Scheduler::sleepList;

    void u_thread::sleep(uthread_id utid,int t)
    {
    Scheduler::sleep(utid,t);
    }
    void u_thread::star_routine()
    {
    u_thread *current_uthread = Scheduler::GetCurrentUThread();
    assert(current_uthread);

    //回到Scheduler::uthread_create
    current_uthread->SetStatus(ACTIVED);
    ucontext_t &cur_context = current_uthread->GetContext();
    swapcontext(&cur_context,&Scheduler::ucontext);

    current_uthread->rable->main_routine();
    current_uthread->SetStatus(DIE);
    }
    void Scheduler::scheduler_init()
    {
    for(int i = 0; i < MAX_UTHREAD; ++i)
    threads[i] = 0;
    getcontext(&ucontext);
    ucontext.uc_stack.ss_sp = stack;
    ucontext.uc_stack.ss_size = sizeof(stack);
    ucontext.uc_link = NULL;
    makecontext(&ucontext,schedule, 0);
    }

    void Scheduler::schedule()
    {
    while(total_count > 0)
    {

    //首先执行active列表中的uthread
    std::list<u_thread*>::iterator it = activeList.begin();
    std::list<u_thread*>::iterator end = activeList.end();
    for( ; it != end; ++it)
    {
    if(*it && (*it)->GetStatus() == ACTIVED)
    {
    ucontext_t &cur_context = (*it)->GetContext();
    swapcontext(&ucontext,&cur_context);
    uthread_id uid = (*it)->GetUid();
    if((*it)->GetStatus() == DIE)
    {
    printf("%d die/n",uid);
    delete threads[uid];
    threads[uid] = 0;
    --total_count;
    activeList.erase(it);
    break;
    }
    else if((*it)->GetStatus() == SLEEP)
    {
    printf("%d sleep/n",uid);
    activeList.erase(it);
    break;
    }
    }
    }
    //看看Sleep列表中是否有uthread该醒来了
    std::list<std::pair<u_thread*,time_t> >::iterator its = sleepList.begin();
    std::list<std::pair<u_thread*,time_t> >::iterator ends = sleepList.end();
    time_t now = time(NULL);
    for( ; its != ends; ++its)
    {
    //可以醒来了
    if(now >= its->second)
    {
    u_thread *uthread = its->first;
    uthread->SetStatus(ACTIVED);
    activeList.push_back(uthread);
    sleepList.erase(its);
    break;
    }
    }
    }

    printf("scheduler end/n");
    }
    uthread_id Scheduler::uthread_create(runnable *rable,unsigned int stacksize)
    {
    if(total_count >= MAX_UTHREAD)
    return INVAID_ID;
    int i = 0;
    for( ; i < MAX_UTHREAD; ++i)
    {
    if(threads[i] == 0)
    {
    threads[i] = new u_thread(rable,stacksize,i);
    ++total_count;
    current = i;
    ucontext_t &cur_context = threads[i]->GetContext();
    cur_context.uc_link = &ucontext;
    makecontext(&cur_context,u_thread::star_routine, 0);
    swapcontext(&ucontext, &cur_context);
    current = -1;
    activeList.push_back(threads[i]);
    return i;
    }
    }
    }
    void Scheduler::sleep(uthread_id utid,int t)
    {
    if(utid == INVAID_ID)
    return;
    assert(threads[utid]);
    time_t now = time(NULL);
    now += t;
    printf("wake up time %u/n",now);
    //插入到sleep列表中
    sleepList.push_back(std::make_pair(threads[utid],now));

    //保存当前上下文切换回scheduler
    threads[utid]->SetStatus(SLEEP);
    ucontext_t &cur_context = threads[utid]->GetContext();
    swapcontext(&cur_context,&Scheduler::ucontext);
    }


    uthreadtest.cpp

    // kcoroutine.cpp : 定义控制台应用程序的入口点。
    //
    #include "uthread.h"
    class runable_test : public runnable
    {
    public:
    runable_test(const char *name):name(name){}
    void main_routine()
    {
    for(int i =0 ; i < 10 ; ++i)
    {
    printf("%s/n",name);
    u_thread::sleep(uid,1);
    printf("%s wake up/n",name);
    }
    }
    const char *name;
    uthread_id uid;
    };
    int main()
    {
    //首先初始化调度器
    Scheduler::scheduler_init();


    runable_test t1("0");
    runable_test t2("1");
    runable_test t3("2");
    runable_test t4("3");

    //创建4个用户级线程
    t1.uid = Scheduler::uthread_create(&t1,4096);
    t2.uid = Scheduler::uthread_create(&t2,4096);
    t3.uid = Scheduler::uthread_create(&t3,4096);
    t4.uid = Scheduler::uthread_create(&t4,4096);

    printf("create finish/n");
    //开始调度线程的运行
    Scheduler::schedule();
    return 0;
    }



    在linux下执行

    g++ -o test uthreadtest.cpp uthread.cpp

    便可生成可执行文件

  • 相关阅读:
    软考数据库设计大观
    软考难点—算法时间的复杂度
    软考数据流图设计大观
    Android底部菜单的封装及重用
    在Action类中获得HttpServletResponse对象的四种方法
    java 单向加密算法
    ASP.NET下FCKeditor配置方法全解
    visual studio 2010 开发net 2.0 3.5项目
    android网络编程
    js 常用页面刷新
  • 原文地址:https://www.cnblogs.com/sniperHW/p/2429640.html
Copyright © 2011-2022 走看看