Orocos Activity&ExecutionEngine 解析

来源:互联网 发布:淘宝gxg官方店是真的吗 编辑:程序博客网 时间:2024/05/22 18:28

Orocos 每一个TaskContext 类表示一个完整的模块,该模块有configure,start,stop,clean,setPeriod等等方法来控制这个模块的运行。如果使用了该模块的 setActivity 方法,该模块将置于一个单独的线程中运行,根据自己的周期频率执行各个函数,读写dataport等。

setActivity 方法如下:

bool TaskContext::setActivity(ActivityInterface* new_act)  // Activity 继承于 ActivityInterface{    if (this->isRunning())        return false;    if ( new_act == 0) {#if defined(ORO_ACT_DEFAULT_SEQUENTIAL)        new_act = new SequentialActivity();#elseif defined(ORO_ACT_DEFAULT_ACTIVITY)        new_act = new Activity();  // 在这new了一个新的Activity,即创建了一个新的线程用于执行该模块。#endif    }    new_act->stop();    if(our_act){        our_act->stop();    }    new_act->run( this->engine() );  // 这个模块所有需要运行的资源都是通过这个 ExecutionEngine 来执行的。    our_act = ActivityInterface::shared_ptr( new_act );    our_act->start();    return true;}

所以说,ExecutionEngine 是通过 Activity 来执行的,而 TaskContext 中的资源又是通过 ExecutionEngine 来执行的。归根到底是通过 Activity 来执行的 :)

其中每一个 Activity 类都表示一个线程:

class Activity : public base::ActivityInterface, public os::Thread

其中 os::Thread 类根据编译时所选择的平台可以是 gnulinux, xenomai, win32等线程的实现:

#ifdef OROPKG_OS_GNULINUX #include "gnulinux/fosi.h"#endif#ifdef OROPKG_OS_LXRT #include "lxrt/fosi.h"#endif#ifdef OROPKG_OS_XENOMAI #include "xenomai/fosi.h"#endif#ifdef OROPKG_OS_ECOS #include "ecos/fosi.h"#endif#ifdef OROPKG_OS_MACOSX  #include "macosx/fosi.h"#endif#ifdef OROPKG_OS_WIN32  #include "win32/fosi.h"#endif

Thread 类结构如下:

class Thread: public ThreadInterface{    friend void* thread_function(void* t);  // 传入Activity的this指针(其中又保存了一个ExecutionEngine的指针),thread_function中实现一个while(1){...}来运行各种Hook,从而驱动顶层的 TaskContext 的运转。public:    Thread(int scheduler, int priority, double period, unsigned cpu_affinity,           const std::string & name);  // 根据条件构造相应的线程    virtual ~Thread();    bool setPeriod(Seconds s);  // 执行周期,也可以为非周期性的    ...private:    Thread(const Thread&);  // noncopiable    ...}

最关键的就是 thread_function 这个函数了,实现了线程的周期性执行,step执行等:

void *thread_function(void* t){    /**     * This is one time initialisation     */    Thread* task = static_cast<os::Thread*> (t);    Logger::In in(task->getName());    task->configure();    // signal to setup() that we're created.    rtos_sem_signal(&(task->sem));    // This lock forces setup(), which holds the lock, to continue.    { MutexLock lock(task->breaker); }#ifdef OROPKG_OS_THREAD_SCOPE    // order thread scope toggle bit on thread number    unsigned int bit = task->threadNumber();#endif    SCOPE_OFF    int overruns = 0, cur_sched = task->msched_type;    NANO_TIME cur_period = task->period;    while (!task->prepareForExit)    {        TRY(            /**             * The real task starts here.             */            while (1)            {                if (!task->active || (task->active && task->period == 0) || !task->running )                {                    // consider this the 'configuration or waiting for command state'                    if (task->period != 0) {                        overruns = 0;                        // drop out of periodic mode:                        rtos_task_set_period(task->getTask(), 0);                    }                    rtos_sem_wait(&(task->sem)); // wait for command.                    task->configure();           // check for reconfigure                    if (task->prepareForExit)    // check for exit                    {                        break; // break while(1) {}                    }                    // end of configuration                }                // This is the running state. Only enter if a task is running                if ( task->running )                {                    if (task->period != 0) // periodic                    {                        MutexLock lock(task->breaker);                        while(task->running && !task->prepareForExit )                        {                            TRY                            (                                SCOPE_ON                                task->step(); // one cycle                                SCOPE_OFF                            )                            CATCH_ALL                            (                                SCOPE_OFF                                throw;                            )                            // Check changes in period                            if ( cur_period != task->period) {                                // reconfigure period before going to sleep                                rtos_task_set_period(task->getTask(), task->period);                                cur_period = task->period;                                if (cur_period == 0)                                    break; // break while(task->running) if no longer periodic                            }                            // Check changes in scheduler                            if ( cur_sched != task->msched_type) {                                rtos_task_set_scheduler(task->getTask(), task->msched_type);                                cur_sched = task->msched_type;                            }                            // rtos_task_wait_period will return immediately if                            // the task is not periodic (ie period == 0)                            // return non-zero to indicate overrun.                            if (rtos_task_wait_period(task->getTask()) != 0)                            {                                ++overruns;                                if (overruns == task->maxOverRun)                                    break; // break while(task->running)                            }                            else if (overruns != 0)                                --overruns;                        } // while(task->running)                        if (overruns == task->maxOverRun || task->prepareForExit)                            break; // break while(1) {}                    }                    else // non periodic:                    TRY                    (                        // this mutex guarantees that stop() waits                        // until loop() returns.                        MutexLock lock(task->breaker);                        task->inloop = true;                        SCOPE_ON                        task->loop();                        SCOPE_OFF                        task->inloop = false;                    ) CATCH_ALL                    (                        SCOPE_OFF                        task->inloop = false;                        throw;                    )                }            } // while(1)            if (overruns == task->maxOverRun)            {                task->emergencyStop();                Logger::In in(rtos_task_get_name(task->getTask()));                log(Critical) << rtos_task_get_name(task->getTask())                        << " got too many periodic overruns in step() ("                        << overruns << " times), stopped Thread !"                        << endlog();                log()   << " See Thread::setMaxOverrun() for info."                        << endlog();            }        )CATCH(std::exception const& e,            SCOPE_OFF            task->emergencyStop();            Logger::In in(rtos_task_get_name(task->getTask()));            log(Critical) << rtos_task_get_name(task->getTask())                    << " caught a C++ exception, stopped thread !"                    << endlog();            log(Critical) << "exception was: "                       << e.what() << endlog();        ) CATCH_ALL        (            SCOPE_OFF            task->emergencyStop();            Logger::In in(rtos_task_get_name(task->getTask()));            log(Critical) << rtos_task_get_name(task->getTask())                    << " caught an unknown C++ exception, stopped thread !"                    << endlog();        )    } // while (!prepareForExit)    return 0;}void Thread::emergencyStop(){    // set state to not running    this->running = false;    this->inloop  = false;    this->active  = false;    // execute finalize in current mode, even if hard.    this->finalize();}
0 0
原创粉丝点击