Orocos Activity&ExecutionEngine 解析

15 篇文章 1 订阅
12 篇文章 5 订阅

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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值