• 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

    便可生成可执行文件

  • 相关阅读:
    java Activiti 工作流引擎 SSM 框架模块设计方案
    自定义表单 Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    数据库设计的十个最佳实践
    activiti 汉化 stencilset.json 文件内容
    JAVA oa 办公系统模块 设计方案
    java 考试系统 在线学习 视频直播 人脸识别 springboot框架 前后分离 PC和手机端
    集成 nacos注册中心配置使用
    “感恩节 ”怼记
    仓颉编程语言的一点期望
    关于System.out.println()与System.out.print("\n")的区别
  • 原文地址:https://www.cnblogs.com/sniperHW/p/2429640.html
Copyright © 2020-2023  润新知