网站数据库查询怎么做,展示展厅设计,吉林律师网站建设多少钱,网站建设方案有哪几种硬件#xff1a;STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、RT-Thread相关接口函数1. 获取当前运行的线程2. 设置调度器钩子函数 二、程序设计1. 头文件包含及宏定义2. 线程入口函数定义3. main函数设… 硬件STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、RT-Thread相关接口函数1. 获取当前运行的线程2. 设置调度器钩子函数 二、程序设计1. 头文件包含及宏定义2. 线程入口函数定义3. main函数设计 三、程序测试总结 前言
本章进一步研究多线程的运行机制。要求实现功能如下创建2个线程线程名称分别为LED和BEEP。两个线程的任务是连续5次打印本线程的名字后退出线程注意线程不执行控制LED和蜂鸣器动作。
设计本任务的目的是观察LED和BEEP线程在操作系统中是如何同时运行的。 一、RT-Thread相关接口函数
1. 获取当前运行的线程
在程序的运行过程中相同的一段代码可能会被多个线程执行在执行的时候可以通过下面的函数接口获得当前执行的线程句柄
rt_thread_t rt_thread_self(void);该接口的返回值见下表
返回描述thread当前运行的线程句柄返回RT_NULL失败调度器还未启动
2. 设置调度器钩子函数
在整个系统的运行时系统都处于线程运行、中断触发和响应中断、切换到其他线程甚至是线程间的切换过程中或者说系统的上下文切换是系统中最普遍的事件。有时用户可能会想知道在一个时刻发生了什么样的线程切换可以通过调用下面的函数接口设置一个相应的钩子函数。在系统线程切换时这个钩子函数将被调用
void rt_scheduler_sethook(void (*hook)(struct rt_thread* from, struct rt_thread* to));设置调度器钩子函数的输入参数如下表所示
参数描述hook表示用户定义的钩子函数指针
钩子函数 hook() 的声明如下
void hook(struct rt_thread* from, struct rt_thread* to);调度器钩子函数 hook() 的输入参数如下表所示
函数参数描述from表示系统所要切换出的线程控制块指针to表示系统所要切换到的线程控制块指针 注请仔细编写你的钩子函数稍有不慎将很可能导致整个系统运行不正常在这个钩子函数中基本上不允许调用系统 API更不应该导致当前运行的上下文挂起。 二、程序设计
使用rt_thread_t rt_thread_self()函数获取本线程的线程句柄然后通过线程句柄可以方便地获得线程地名称。对main.c进行如下程序设计
1. 头文件包含及宏定义
本任务代码中我们使用预编译宏进行选择编译使代码可以兼容两个版本提高代码利用率
#include rtthread.h
#define DBG_TAG main
#define DBG_LVL DBG_LOG
#include rtdbg.h
//#include car_led.h //包含LED控制模块头文件
//#include car_beep.h //包含蜂鸣器控制模块头文件#define THREAD_STACK_SIZE 1024 //定义线程栈大小
//两个线程优先级分别定义
#define THREAD_PRIORITY_LED 20
#define THREAD_PRIORITY_BEEP 20
#define THREAD_TIMESLICE 10 //定义线程时间片/*使用预编译宏进行选择编译,当定义以下宏时讲开启调度器钩子功能*/
//#define SCHEDULER_HOOK#ifdef SCHEDULER_HOOK
//定义调度钩子函数
static void hook_of_scheduler(struct rt_thread* from,struct rt_thread* to)
{//打印调度信息从一个线程切换到另一个线程运行rt_kprintf(from: %s -- to: %s \nfrom-name,to-name);
}
#endif2. 线程入口函数定义
本任务需要创建两个线程所以要编写两个线程入口函数分别为beep_thread_entry和led_thread_entry。
void beep_thread_entry(void * parameter)
{rt_thread_t tid;int count 0; //打印出前5个调度过程while(1){tid rt_thread_self(); //获取本线程地句柄//打印线程的名字和当前计数变量地值LOG_D(thread name: %s count %d\n,tid-name,count);if (count 5) //线程循环5次后退出 break; }//线程退出时打印退出信息LOG_D(thread %s exit\n,tid-name);
}void led_thread_entry()
{rt_thread_t tid;int count 0; //打印出前5个调度过程while(1){tid rt_thread_self(); //获取本线程地句柄//打印线程的名字和当前计数变量地值LOG_D(thread name: %s count %d\n,tid-name,count);if (count 5) //线程循环5次后退出 break; }//线程退出时打印退出信息LOG_D(thread %s exit\n,tid-name);
}3. main函数设计
main只负责线程的创建用动态的方法创建LED线程静态方法创建beep线程。静态方法需要用户自定义线程栈空间和线程控制块。
/* 栈首地址必须系统对齐 */
ALIGN(RT_ALIGN_SIZE)
static char beep_stack[THREAD_STACK_SIZE]; //定义栈空间
static struct rt_thread beepThread; //静态方式定义beep线程控制块
rt_thread_t TidLed RT_NULL; //动态方式定义LED线程句柄int main(void)
{int ret;#ifdef SCHEDULER_HOOK
//设置调度钩子rt_scheduler_sethook(hook_of_scheduler);#endif/* 动态方式创建线程 */TidLed rt_thread_create(LED, led_thread_entry, RT_NULL,THREAD_STACK_SIZE, THREAD_PRIORITY_LED,THREAD_TIMESLICE);if (TidLed ! RT_NULL)//判断线程是否成功创建rt_thread_startup(TidLed);//成功则启动线程else {//否则打印日志并即出LOG_D(can not create LED thread!);return -1;}/* 采用静态方式初始化线程 */ret rt_thread_init(beepThread,BEEP,beep_thread_entry,RT_NULL,beep_stack[0],sizeof(beep_stack),THREAD_PRIORITY_BEEP,THREAD_TIMESLICE);if (ret RT_EOK) //判断线程是否成功创建rt_thread_startup(beepThread); //成功则启动线程else { //否则打印日志并即出LOG_D(can not init beep thread!);return -1;}return RT_EOK;
}三、程序测试
1使用终端连接开发板然后按开发板reset键重启系统终端调试信息如下图发现两个线程轮流输出信息可以间接说明两个线程时轮流执行的。 2把BEEP优先级改为19修改后按照1进行测试如图所示即使LED线程先于BEEP线程创建由于BEEP线程的优先级高于LED线程因此BEEP线程被执行LED要等BEEP执行完后再执行。 3打开预处理宏定义#define SCHEDULER_HOOK把LED和BEEP优先级都设置为20重新构建并下载。由下图可以看到系统先运行main线程再运行tshell线程这是因为系统中main线程优先级默认为10比tshell默认优先级20高所以系统先运行main线程。
tshell运行后LED线程和BEEP线程接着轮流运行由于这3个线程的优先级都是20所以他们在属于同一个优先级的队列中并且按启动先后顺序排列注意是启动顺序即rt_thread_startup函数的执行顺序而不是创建程序调度顺序也是按照启动的先后顺序进行的。
LED线程和BEEP线程退出后进入tidle0线程运行tidle0优先级在系统中最低当所有高优先级的线程退出或者睡眠时会进入tidle0线程运行。 4打开预处理宏定义#define SCHEDULER_HOOK把LED和BEEP优先级分别设置为20、19。 修改后重新构建并下载程序观察终端如图所示。系统运行顺序为 main线程→BEEP线程→tshell线程→LED线程 总结
在操作系统中所有线程各自独立运行所有线程看起来是同时工作的但在只有一个CPU核的情况下在同一时刻只能有一个线程在CPU上运行操作系统为每个线程分配一定的运行时间片当线程的运行时间耗尽时操作系统会调度下一个线程到CPU运行。由于时间片很小使得我们觉得线程是在同时运行的。