本节主要记录ardupilot chibios如何创建一个线程,欢迎批评指正。
在使用RTOS时,创建一个新线程是最常见的开发任务,这是在chibios/rt中完成的。
在使用chibios/rt的初始化 chsysinit()之后,默认情况下会生成两个线程:
/**************************************************************************************************************
*函数原型: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
}
chibios/rt中有两类线程:
为了创建静态线程,必须使用宏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()的内存是静态定义的,**不能重复使用。**静态线程是安全应用程序的理想选择,因为不存在由于渐进堆碎片而导致内存分配失败的风险。
从内存堆创建线程非常简单:
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);
.
.
}
共享资源是大小相等的内存块的集合,从内存池创建线程与前面的示例非常相似,但终止线程的内存返回到内存池而不是堆:
/*
* 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);
.
.
}