动态内存管理
示例:
char *ptr = RT_NULL;
ptr = (char *)rt_malloc(10);
...
if(ptr!=RT_NULL)//如果分配成功
{
rt_memset(ptr, 0, 10);//清0,内存复位
}
...
rt_free(ptr);//释放内存,防止内存泄漏
ptr = RT_NULL;//防止成为野指针
堆的地址范围配置:
动态内存分配是在heap堆中
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
END地址 - BEGIN地址
在已分配的内存块的基础上重新分配内存块的大小
void *rt_realloc(void *rmem, rt_size_t newsize);
增加或者缩小,增大原数据没影响,缩小,后面的数据自动截断。
从内存堆中分配连续内存地址的多个内存块
void *rt_calloc(rt_size_t count, rt_size_t size)
GPIO配置
对应引脚输入输出模式
rt_pin_mode(14, PIN_MODE_OUTPUT);//14:drv_gpio.c查看对应引脚
输出,io高低电平
rt_pin_write(14, PIN_LOW);//PIN_HIGH
输入,读取io高低电平状态
rt_pin_read(14);
线程创建
1)动态线程创建
static rt_thread_t tid1 = RT_NULL;//rt_thread_t是rt_thread类型指针
static void thread1_entry(void *parameter){...}//线程入口函数
tid1 = rt_thread_create("thread1",
thread1_entry,
RT_NULL,
512,
25,
5);
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
2)静态线程创建
static char thread2_stack[1024];//线程堆地址数组
static struct rt_thread thread2;//创建线程控制块
static void thread2_entry(void *parameter){...}//线程入口函数
rt_thread_init(&thread2,//线程控制块起始地址
"thread2",//线程名字
thread2_entry,//线程入口函数
RT_NULL,//入口函数形参
&thread2_stack[0],//线程堆地址起始地址
sizeof(thread2_stack),//线程堆地址大小
THREAD_PRIORITY - 1, //优先级
THREAD_TIMESLICE);//时间分片
if (thread2 != RT_NULL)
rt_thread_startup(&thread2);//线程启动函数,加入线程就绪队列,执行调度
THREAD_TIMESLICE);//时间分片:
时间片只在相同优先级的就绪态线程起作用,系统对优先级相同的就绪态线程采用时间片轮转的调度方式进行调度,时间片起到约束线程单次运行时长的作用,单位是一个系统节拍。
假设有2个优先级相同都为n的就绪态线程A和B,A时间片设置为10,B时间片设置为5,当系统中不存在比A,B优先级高的就绪态线程时,系统会在A,B线程间来回切换执行,并且每次对A执行10个系统节拍的时长,对B执行5个系统节拍时长。
线程状态
空闲线程与两个钩子函数
空闲线程
空闲线程是特殊的系统线程,它的优先级最低,当系统中无其他就绪线程可执行的时候,调度器将调度到空闲线程,空闲线程一直是不会挂起的状态。
空闲线程钩子函数
空闲线程钩子函数:系统在调用空闲线程的时候执行的一些非紧急事务的函数,如打印一些信息,指示灯闪烁等。
空闲线程一般可以设置4个空闲线程钩子函数,而且因为空闲线程一直不会挂起的原因,空闲线程钩子函数中不能调用可能导致挂起的函数。(rt_thread_delay(); rt_sem_take(); 等)
设置空闲线程钩子函数
rt_err_t rt_thread_idle_sethook(void(*hook)(void));
删除空闲线程钩子函数
rt_err_t rt_thread_idle_delhook(void(*hook)(void));
示例
/* 设置空闲线程钩子 */
rt_thread_idle_sethook(idle_hook);
/* 空闲任务钩子函数 */
static void idle_hook()
{
...
}
/* 删除空闲钩子函数 */
rt_thread_idle_delhook(idle_hook);
系统调度钩子函数
系统调度钩子函数:在系统进行任务切换的时候运行,打印系统任务调度时候的一些信息。
只能有一个系统调度钩子函数。
rt_scheduler_sethook( void(*hook)(struct rt_thread *from, struct rt_thread *to) );
示例:
/* 设置调度器钩子 */
rt_scheduler_sethook(hook_of_scheduler);
/*系统调度钩子函数*/
static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to)
{
rt_kprintf("from: %s --> to: %s \n", from->name , to->name);
}
临界区保护
临界资源
一次只允许一个线程访问的共享资源,多个线程必须互斥地进行访问。
临界区
线程中对临界资源进行操作的代码段
临界区保护
1)禁止调度
不能切换线程,仅响应中断。
void thread_entry( void * parameter )
{
while(1)
{
/*调度器上锁,不能切换到其他线程,仅响应中断*/
rt_enter_critical();
/*临界区*/
...
/*调度器解锁*/
rt_exit_critical();
}
}
2)关闭中断
系统调度是建立在中断的基础上,关闭中断,系统自然无法进行调度。
void thread_entry( void * parameter )
{
rt_base_t level;//中断状态
while(1)
{
/*关闭中断*/
level = rt_hw_interrupt_disable();
/*临界区*/
...
/*开启中断*/
rt_hw_interrupt_enable(level);
}
}