ardupilot chibios如何创建一个线程

目录

文章目录

  • 目录
  • 摘要
  • 1.如何创建线程
    • 1.默认线程
    • 2.线程类
      • 1.创建一个静态线程
      • 2.使用堆分配器创建动态线程
      • 3.使用共享资源创建动态线程

摘要


本节主要记录ardupilot chibios如何创建一个线程,欢迎批评指正。


1.如何创建线程

在使用RTOS时,创建一个新线程是最常见的开发任务,这是在chibios/rt中完成的。

ardupilot chibios如何创建一个线程_第1张图片


1.默认线程

在使用chibios/rt的初始化 chsysinit()之后,默认情况下会生成两个线程:

  • 空闲线程(Idle thread)。这个线程在系统中的优先级最低,因此它只在系统中的其他线程休眠时运行。这个线程通常在低功耗模式下切换系统,而不执行其他任何操作。
  • 主线程(Main thread)。这个线程在启动时执行main()函数。主线程是在NORMALPRIO级别创建的,但如果需要,它可以更改自己的优先级。其他线程通常是从主线程创建的。
/**************************************************************************************************************
*函数原型:void __late_init(void)
*函数功能:后期初始化
*修改日期:2019-6-4
*修改作者:dzuav
*备注信息:
****************************************************************************************************************/
void __late_init(void)
{
  halInit();
  chSysInit(); //会创建两个线程,空闲线程和主线程
#if CH_CFG_USE_HEAP == TRUE
  malloc_init();
#endif
#ifdef HAL_USB_PRODUCT_ID
  setup_usb_strings();
#endif
}



/**
 * @brief   ChibiOS/RT initialization.
 * @details After executing this function the current instructions stream
 *          becomes the main thread.
 * @pre     Interrupts must disabled before invoking this function.
 * @post    The main thread is created with priority @p NORMALPRIO and
 *          interrupts are enabled.
 *
 * @special
 */
void chSysInit(void) {

  _scheduler_init();
  _vt_init();
  _trace_init();

#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
  ch.dbg.isr_cnt  = (cnt_t)0;
  ch.dbg.lock_cnt = (cnt_t)0;
#endif
#if CH_CFG_USE_TM == TRUE
  _tm_init();
#endif
#if CH_CFG_USE_MEMCORE == TRUE
  _core_init();
#endif
#if CH_CFG_USE_HEAP == TRUE
  _heap_init();
#endif
#if CH_DBG_STATISTICS == TRUE
  _stats_init();
#endif

#if CH_CFG_NO_IDLE_THREAD == FALSE
  /* Now this instructions flow becomes the main thread.*/
#if CH_CFG_USE_REGISTRY == TRUE
  currp = _thread_init(&ch.mainthread, (const char *)&ch_debug, NORMALPRIO); //主线程初始化
#else
  currp = _thread_init(&ch.mainthread, "main", NORMALPRIO);
#endif
#else
  /* Now this instructions flow becomes the idle thread.*/
  currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO); //空闲线程初始化
#endif

#if CH_DBG_ENABLE_STACK_CHECK == TRUE
  {
    /* Setting up the base address of the static main thread stack, the
       symbol must be provided externally.*/
    extern stkalign_t __main_thread_stack_base__;
    currp->wabase = &__main_thread_stack_base__;
  }
#elif CH_CFG_USE_DYNAMIC == TRUE
  currp->wabase = NULL;
#endif

  /* Setting up the caller as current thread.*/
  currp->state = CH_STATE_CURRENT;

  /* Port layer initialization last because it depend on some of the
     initializations performed before.*/
  port_init();

#if CH_DBG_STATISTICS == TRUE
  /* Starting measurement for this thread.*/
  chTMStartMeasurementX(&currp->stats);
#endif

  /* It is alive now.*/
  chSysEnable();

#if CH_CFG_NO_IDLE_THREAD == FALSE
  {
    static const thread_descriptor_t idle_descriptor = {
      "idle",
      THD_WORKING_AREA_BASE(ch_idle_thread_wa),
      THD_WORKING_AREA_END(ch_idle_thread_wa),
      IDLEPRIO,
      _idle_thread,
      NULL
    };

    /* This thread has the lowest priority in the system, its role is just to
       serve interrupts in its context while keeping the lowest energy saving
       mode compatible with the system status.*/
    (void) chThdCreate(&idle_descriptor);
  }
#endif
}


2.线程类

chibios/rt中有两类线程:

  • 静态线程。这类线程在编译时在内存中静态分配。
  • 动态线程。在运行时从内存堆或内存池分配内存而创建的线程。

1.创建一个静态线程

为了创建静态线程,必须使用宏THD_WORKING_AREA声明工作区,如图所示:

static THD_WORKING_AREA(myThreadWorkingArea, 128);

此宏为线程保留128字节的堆栈,并为所有所需的线程相关结构保留空间。总大小和对齐问题是在宏内部处理的,您只需要指定所需的纯堆栈大小和简单堆栈大小。

静态线程可以通过调用**chThdCreateStatic()**启动,如本例所示:

 thread_t *tp = chThdCreateStatic(myThreadWorkingArea,
                                   sizeof(myThreadWorkingArea),
                                   NORMALPRIO,  /* Initial priority.    */
                                   myThread,    /* Thread function.     */
                                   NULL);       /* Thread parameter.    */

ardupilot中的静态线程

THD_WORKING_AREA(_timer_thread_wa, 2048);
THD_WORKING_AREA(_rcin_thread_wa, 512);
THD_WORKING_AREA(_io_thread_wa, 2048);
THD_WORKING_AREA(_storage_thread_wa, 2048);
#if HAL_WITH_UAVCAN
THD_WORKING_AREA(_uavcan_thread_wa, 4096);
#endif

void Scheduler::init()
{
    chBSemObjectInit(&_timer_semaphore, false);
    chBSemObjectInit(&_io_semaphore, false);
    // setup the timer thread - this will call tasks at 1kHz
    _timer_thread_ctx = chThdCreateStatic(_timer_thread_wa,
                     sizeof(_timer_thread_wa),
                     APM_TIMER_PRIORITY,        /* 初始化优先级----Initial priority.    */
                     _timer_thread,             /* 线程函数----Thread function.     */
                     this);                     /*线程指针------Thread parameter.    */

    // setup the uavcan thread - this will call tasks at 1kHz
#if HAL_WITH_UAVCAN
    _uavcan_thread_ctx = chThdCreateStatic(_uavcan_thread_wa,
                     sizeof(_uavcan_thread_wa),
                     APM_UAVCAN_PRIORITY,        /* Initial priority.    */
                     _uavcan_thread,            /* Thread function.     */
                     this);                     /* Thread parameter.    */
#endif
    // setup the RCIN thread - this will call tasks at 1kHz
    _rcin_thread_ctx = chThdCreateStatic(_rcin_thread_wa,
                     sizeof(_rcin_thread_wa),
                     APM_RCIN_PRIORITY,        /* Initial priority.    */
                     _rcin_thread,             /* Thread function.     */
                     this);                     /* Thread parameter.    */

    // the IO thread runs at lower priority
    _io_thread_ctx = chThdCreateStatic(_io_thread_wa,
                     sizeof(_io_thread_wa),
                     APM_IO_PRIORITY,        /* Initial priority.      */
                     _io_thread,             /* Thread function.       */
                     this);                  /* Thread parameter.      */

    // the storage thread runs at just above IO priority
    _storage_thread_ctx = chThdCreateStatic(_storage_thread_wa,
                     sizeof(_storage_thread_wa),
                     APM_STORAGE_PRIORITY,        /* Initial priority.      */
                     _storage_thread,             /* Thread function.       */
                     this);                  /* Thread parameter.      */
}



变量tp接收到一个指向线程对象的指针,这个指针通常被其他API作为参数。现在是一个完整的例子:

/*
 * My simple application.
 */
 
#include 
 
/*
 * Working area for the LED flashing thread.
 */
static THD_WORKING_AREA(myThreadWorkingArea, 128); //声明工作区
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  while (true) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
  }
}
 
int main(int argc, char *argv[]) {
 
  /* Starting the flashing LEDs thread.*/
  (void)chThdCreateStatic(myThreadWorkingArea, sizeof(myThreadWorkingArea),
                          NORMALPRIO, myThread, NULL);
  .
  .
  .
}

请注意,分配给mythread()的内存是静态定义的,**不能重复使用。**静态线程是安全应用程序的理想选择,因为不存在由于渐进堆碎片而导致内存分配失败的风险。


2.使用堆分配器创建动态线程

从内存堆创建线程非常简单:

thread_t *tp = chThdCreateFromHeap(NULL,          /* NULL = Default heap. */
                                     THD_WORKING_AREA_SIZE(128), /* Stack.  */
                                     "name",        /* Thhread name.        */
                                     NORMALPRIO,    /* Initial priority.    */
                                     myThread,      /* Thread function.     */
                                     NULL);         /* Thread parameter.    */
void UARTDriver::thread_init(void)
{
    if (uart_thread_ctx)
    {
        // already initialised
        return;
    }
#if CH_CFG_USE_HEAP == TRUE
    uart_thread_ctx = chThdCreateFromHeap(NULL,
                                          THD_WORKING_AREA_SIZE(2048),
                                          "apm_uart",
                                          APM_UART_PRIORITY,
                                          uart_thread,
                                           this);
#endif
}

内存是从指定的堆分配的,线程是启动的。请注意,当线程终止时,内存不会释放,但当线程最终状态由生成线程收集时,内存会释放。例如:

/*
 * My simple application.
 */
 
#include 
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  chthdExit((msg_t)i);
}
 
int main(int argc, char *argv[]) {
 
  thread_t *tp = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(128),
                                     "name", NORMALPRIO+1, myThread, NULL);
  if (tp == NULL)
    chSysHalt("out of memory");
 
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the heap (default system heap in this
   * example).
   */
  msg_t msg = chThdWait(tp);
  .
  .
}

3.使用共享资源创建动态线程

共享资源是大小相等的内存块的集合,从内存池创建线程与前面的示例非常相似,但终止线程的内存返回到内存池而不是堆:

/*
 * My simple application.
 */
 
#include 
 
/*
 * LED flashing thread.
 */
static THD_FUNCTION(myThread, arg) {
 
  unsigned i = 10;
  while (i > 0) {
    LED_ON();
    chThdSleepMilliseconds(500);
    LED_OFF();
    chThdSleepMilliseconds(500);
    i--;
  }
  chthdExit((msg_t)i);
}
 
int main(int argc, char *argv[]) {
 
  thread_t *tp = chThdCreateFromMemoryPool(myPool, NORMALPRIO+1,
                                           "name", myThread, NULL);
  if (tp == NULL)
    chSysHalt("pool empty");
 
  /* The main thread continues its normal execution.*/
  .
  .
  /*
   * Now waits for the spawned thread to terminate (if it has not terminated
   * already) then gets the thread exit message (msg) and returns the
   * terminated thread memory to the original memory pool.
   */
  msg_t msg = chThdWait(tp);
  .
  .
}

你可能感兴趣的:(ardupilot学习)