RT-Thread学习笔记

####RT-Thread学习之——静态线程和动态线程
RT-Thread中支持静态和动态两种定义方式。

用线程来举例的话,rt_thread_init对应静态定义方式,rt_thread_create对应动态定义方式。

使用静态定义方式时,必须先定义静态的线程控制块,并且定义好堆栈空间,然后调用rt_thread_init来完成线程的初始化工作。采用这种方式,线程控制块和堆栈占用的内存会放在RW段,这段空间在编译时就已经确定,它不是可以动态分配的,所以不能被释放。而只能使用rt_thread_detach函数将该线程控制块从对象管理器中脱离。

使用动态定义方式rt_thread_create时,RT-Thread会动态申请线程控制块和堆栈空间。在编译时,编译器是不会感知到这段空间的,只有在程序运行时,RT-Thread才会从系统堆中申请分配这段内存空间,当不需要使用该线程时,调用rt_thread_delete函数就会将这段申请的内存空间重新释放到内存堆中。

这两种方式各有利弊,
静态定义方式会占用RW空间,但是不需要动态分配内存,运行时效率高。
动态方式不会占用额外的RW空间,占用空间小,但是运行时需要动态分配内存,效率没有静态方式高。
总的来说,这两种方式就是空间和时间效率的平衡,可以根据实际环境需求选择采用具体的分配方式。

####**线程调度与管理:
1.components.c文件的140行看到#ifdef RT_USING_USER_MAIN宏定义判断,这个宏是定义在rtconfig.h文件内的,而且处于开启状态。同时我们可以在146行看到#if defined (__CC_ARM)的宏定义判断,__CC_ARM就是指keil的交叉编译器名称。
2.除中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占之外,其他部分是可以抢占的,包括线程调度器本身。
3.线程总共支持256个优先级,数值越小优先级越高。
4.线程控制块由结构体struct rt_thread表示
rt_thread_t表示线程的句柄。
5.线程的五种状态:
RT_THREAD_INIT 初始状态
RT_THREAD_READY 就绪状态
RT_THREAD_RUNNIG 运行状态
RT_THREAD_SUSPEND 挂起状态
RT_THREAD_CLOSE 结束状态
6.当系统中无其他线程运行时,调度器将调度到空闲线程。空闲线程通常是一个死循环,永远不会被挂起。

7.调度器相关的接口
(1)调度器初始化   void rt_system_scheduler_init(void);
  (2)启动调度器       void rt_system_scheduler_start(void);
  (3)执行调度           void rt_schedule(void);
  (4)设置调度器钩子  void rt_thread_sethook(void (*hook)(struct rt_thread* from,struct rt_thread* to))  //线程切换时,调度器钩子函数将被调用,用于用户间线程切换
   		void hook(struct rt)_thread* from,struct rt_thread* to);//用于系统间线程切换。

8.线程栈空间的大小确定,可以先指定一个稍微大一点的栈空间,再荣国FinSH shell中通过list_thread()命令查看线程运行的过程。

9.线程相关接口
  (1)线程创建
	rt_thread_t rt_thread_create(const char* name,
			           void (*entry)(void* parameter), void* parameter,
			            rt_uint32_t stack_size,
			            rt_uint8_t priority, rt_uint32_t tick);
   (2)线程删除
	rt_err_t rt_thread_delete(rt_thread_t thread);
  (3)线程初始化
	rt_err_t rt_thread_init(struct rt_thread* thread,
			 const char* name,
			 void (*entry)(void* parameter), void* parameter,
			 void* stack_start, rt_uint32_t stack_size,
			 rt_uint8_t priority, rt_uint32_t tick);

   (4)线程脱离  
	rt_err_t rt_thread_detach (rt_thread_t thread);
   (5)线程启动 
	rt_err_t rt_thread_startup(rt_thread_t thread);
   (6)当前线程
	rt_thread_t rt_thread_self(void);
   (7)线程让出处理器
	rt_err_t rt_thread_yield(void);
   (8)线程睡眠
	rt_err_t rt_thread_sleep(rt_tick_t tick);
	rt_err_t rt_thread_delay(rt_tick_t tick);
   (9)线程挂起
	rt_err_t rt_thread_suspend (rt_thread_t thread);
   (10)线程恢复
	rt_err_t rt_thread_resume (rt_thread_t thread);
   (11)线程控制(例如动态更改线程的优先级)
	rt_err_t rt_thread_control(rt_thread_t thread, rt_uint8_t cmd, void* arg);
   (12)初始化空闲线程
	void rt_thread_idle_init(void);
   (13)设置空闲线程钩子
	void rt_thread_idle_sethook(void (*hook)(void));

10.线程设计
RT-Thread中程序运行的上下文包括:
*中断服务例程
*普通线程
*空闲线程

####**定时器管理:

1.软件定时器的最主要目的是:在经过设定的时间后,系统能够自动执行用户设定的动作。当定时器到了,即超时了,执行的动作函数称之为超时函数。

2.定时器管理接口:
(1)定时器管理系统初始化。
        void rt_system_timer_init(void);
(2)创建定时器
        rt_timer_t rt_timer_create(const char* name,
void (*timeout)(void* parameter), void* parameter,
rt_tick_t time, rt_uint8_t flag);
(3)删除定时器
        rt_err_t rt_timer_delete(rt_timer_t timer);	
(4)初始化定时器
        void rt_timer_init(rt_timer_t timer,
						   const char* name, void (*timeout)(void* parameter), void* parameter,
						   rt_tick_t time, rt_uint8_t flag);
 (5)脱离定时器
        rt_err_t rt_timer_detach(rt_timer_t timer);
 (6)启动定时器
        rt_err_t rt_timer_start(rt_timer_t timer);
 (7)停止定时器
         rt_err_t rt_timer_stop(rt_timer_t timer);
 (8)控制定时器
        rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);

####**任务间同步通信
核心思想:在访问临界区的时候只允许一个(或者一类)任务运行。

1.关闭中断
关闭中断也叫中断锁,是禁止多任务访问临界区最简单的一种方式。
关闭中断函数:rt_base_t rt_hw_interrupt_disable(void);
恢复中断函数:void rt_hw_interrupt_enable(rt_base_t level);

2.调度器锁
与中断锁一样把调度器锁住也能让当前运行的任务不被换出,值到任务调度器解锁。不同之处是对调度器上锁,系统依然能够相应外部中断,中断服务例程依然能进行相应的响应。
调度锁操作API为:
void rt_enter_critical(void); /* 进入临界区*/
void rt_exit_critical(void); /* 退出临界区*/
注: rt_enter_critical/rt_exit_critical可以多次嵌套调用,但每调用一次rt_enter_critical
就必须相对应地调用一次rt_exit_critical退出操作,嵌套的最大深度是65535。

3.信号量
信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取和释放它,从而达到同步或者互斥的目的。

.信号量相关的函数接口
(1)创建信号量
		rt_sem_t rt_sem_create (const char* name, rt_uint32_t value, rt_uint8_t flag); 
(2)删除信号量
		rt_err_t rt_sem_delete (rt_sem_t sem);		
(3)初始化信号量
		rt_err_t rt_sem_init (rt_sem_t sem, const char* name, rt_uint32_t value, rt_uint8_t flag);
(4)脱离信号量
		rt_err_t rt_sem_detach (rt_sem_t sem);
(5)获取信号量
		rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time);
(6)无等待获取信号量
		rt_err_t rt_sem_trytake(rt_sem_t sem);
(7)释放信号量
		rt_err_t rt_sem_release(rt_sem_t sem);
5.互斥量
互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。
互斥量的状态:开锁或闭锁。
(1)创建互斥量
	rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);
(2)删除互斥量
	rt_err_t rt_mutex_delete (rt_mutex_t mutex);
(3)初始化互斥量
	rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);
(4)脱离互斥量
	rt_err_t rt_mutex_detach (rt_mutex_t mutex);
(5)获取互斥量
	rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);
(6)释放信号量
	rt_err_t rt_mutex_release(rt_mutex_t mutex);
6.事件
事件主要用于线程间的同步,与信号量不同,它的特点是实现一对多,多对多的同步。
RT-Thread定义的事件有以下特点:
*事件只与线程相关,事件间相互独立:每个线程拥有32个事件标志,采用一个32bit无符号整型数进行记录,每一个bit代表一个事件。若干个事件构成一个事件集;
*事件仅用于同步,不提供数据传输功能;
*事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次。
每个线程都拥有一个事件信息标记,它有三个属性:
	逻辑与:RT_EVENT_FLAG_END
	逻辑或:RT_EVENT_FLAG_OR
	清除标记:RT_EVENT_FLAG_CLEAR
其实关于事件,你可以理解为一系列的标记位,当标记位接收有效,则触发线程中的程序。

事件相关接口:
(1)创建线程
	rt_event_t rt_event_create (const char* name, rt_uint8_t flag);
(2)删除事件
	rt_err_t rt_event_delete (rt_event_t event);
(3)初始化事件
	rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);
(4)脱离事件
	rt_err_t rt_event_detach(rt_event_t event);
(5)接收事件
	rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option,
rt_int32_t timeout, rt_uint32_t* recved);
(6)发送事件
	rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
	7.邮箱
邮箱服务是实时操作系统中一种典型的任务间通信方法,特点是开销比较低,效率较
高。
每封邮件只能容纳固定的4个字节内容。
邮箱的相关接口
(1)创建邮箱
	rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag);
(2)删除邮箱
	rt_err_t rt_mb_delete (rt_mailbox_t mb);
(3)初始化邮箱
	rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool,
rt_size_t size, rt_uint8_t flag)
(4)脱离邮箱
	rt_err_t rt_mb_detach(rt_mailbox_t mb);
(5)发送邮箱
	rt_err_t rt_mb_send (rt_mailbox_t mb, rt_uint32_t value);
(6)等待方式发送邮箱
	rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_uint32_t value, rt_int32_t timeout);
(7)接收邮箱
	rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_uint32_t* value, rt_int32_t timeout);
8.消息队列
消息队列是另一种常用的线程通讯方式,它能够接收来自线程或中断服务例程中不固定长度的消息。
8.消息队列

消息队列是另一种常用的线程通讯方式,它能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。
消息队列相关接口
(1)创建消息队列
rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag);
(2)删除消息队列
rt_err_t rt_mq_delete(rt_mq_t mq);
(3)初始化消息队列
rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void msgpool, rt_size_t msg_size, rt_size_t pool_size,
rt_uint8_t flag);
(4)脱离消息队列
rt_err_t rt_mq_detach(rt_mq_t mq);
(5)发送消息
rt_err_t rt_mq_send (rt_mq_t mq, void
buffer, rt_size_t size);
(6)发送紧急消息
rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);
(7)接收消息
rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer, rt_size_t size, rt_int32_t timeout);

内存管理
通常存储空间可以分为两种:内部存储空间和外部存储空间。
RT-Thread操作系统在内存管理上分为:静态分区内存管理与动态内存管理。
动态内存管理又根据内存的多少划分为两种情况:一种是针对小内存块的分配管理(小内存管理算法),另一种是针对大内存块的分配管理(SLAB管理算法)。
静态内存池管理
静态内存池接口
(1)创建内存池
rt_mp_t rt_mp_create(const char* name, rt_size_t block_count, rt_size_t block_size);
(2)删除内存池
rt_err_t rt_mp_delete(rt_mp_t mp);
(3)初始化内存池
rt_err_t rt_mp_init(rt_mp_t mp, const char* name, void *start, rt_size_t size, rt_size_t block size);
(4)脱离内存池
rt_err_t rt_mp_detach(rt_mp_t mp);
(5)分配内存块

F

你可能感兴趣的:(RT-Thread)