Rt-Thread 移植6--多线程(KF32)

6.1 就绪列表

6.1.1 线程就绪优先级组

线程优先级表的索引对应的线程的优先级。
在这里插入图片描述
为了快速的找到线程在线程优先级表的插入和移出的位置,RT-Thread专门设计了一个线程就绪优先级组。线程就绪优先组是一个32位的整型数,每一个位对应一个优先级,最多表示32个优先级

rt_uint32_t  rt_thread_ready_priority_group;

在这里插入图片描述

6.1.2 寻找优先级最高的线程

在这里插入图片描述
在这里插入图片描述

从图中看出,第一个置1的位是位1,即表示此时就绪的线程当中,优先级最高的线程1,然后调度器从线程优先级表的索引1下去除线程1的线程控制块,从而切换到线程1.
kservice.c中

const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
int __rt_ffs(int value)
{
    if (value == 0) return 0;

    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;

    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;

    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}

6.1.3 线程优先级表

scheduler.c

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

在这里插入图片描述
将线程插入到线程优先级表和移出分别由scheduler.c的rt_schedule_insert_thread()和rt_schedule_remove_thread()这两个函数实现。

void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;


    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* change stat */
    thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);

    /* insert thread to ready list */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                          &(thread->tlist));


    /* set priority mask */


#if RT_THREAD_PRIORITY_MAX > 32
    rt_thread_ready_table[thread->number] |= thread->high_mask;
#endif
    rt_thread_ready_priority_group |= thread->number_mask;

    P_DBG("insert thread %x grout %x\n",thread,rt_thread_ready_priority_group);
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
}

/*
 * This function will remove a thread from system ready queue.
 *
 * @param thread the thread to be removed
 *
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;



    /* disable interrupt */
    temp = rt_hw_interrupt_disable();


    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {

        rt_thread_ready_priority_group &= ~thread->number_mask;

    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
}

6.2 修改代码

6.2.1 修改线程控制块

struct rt_thread
{
	char name[RT_NAME_MAX];
	rt_uint8_t type;
	rt_uint8_t flag;
	rt_list_t list;
	void        *sp;	          /* 线程栈指针 */
	void        *entry;	          /* 线程入口地址 */
	void        *parameter;	      /* 线程形参 */	
	void        *stack_addr;      /* 线程起始地址 */
	rt_uint32_t stack_size;       /* 线程栈大小,单位为字节 */
	
	rt_list_t   tlist;            /* 线程链表节点 */
#if TEST_USE_TICK_ENABLE
	rt_ubase_t init_tick;
	rt_ubase_t remaining_tick;
#endif
	**rt_uint8_t current_priority;
	rt_uint8_t init_priority;
	rt_uint32_t number_mask;
	rt_err_t error;
	rt_uint8_t stat;**

};

rtdef.h中定义错误码

#define RT_EOK                          0               /**< There is no error */
#define RT_ERROR                        1               /**< A generic error happens */
#define RT_ETIMEOUT                     2               /**< Timed out */
#define RT_EFULL                        3               /**< The resource is full */
#define RT_EEMPTY                       4               /**< The resource is empty */
#define RT_ENOMEM                       5               /**< No memory */
#define RT_ENOSYS                       6               /**< No system */
#define RT_EBUSY                        7               /**< Busy */
#define RT_EIO                          8               /**< IO error */
#define RT_EINTR                        9               /**< Interrupted system call */
#define RT_EINVAL                       10              /**< Invalid argument */

定义线程状态

#define RT_THREAD_INIT                  0x00                /**< Initialized status */
#define RT_THREAD_READY                 0x01                /**< Ready status */
#define RT_THREAD_SUSPEND               0x02                /**< Suspend status */
#define RT_THREAD_RUNNING               0x03                /**< Running status */
#define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /**< Blocked status */
#define RT_THREAD_CLOSE                 0x04                /**< Closed status */
#define RT_THREAD_STAT_MASK             0x0f

修改rt_system_scheduler_init()

void rt_system_scheduler_init(void)
{



	register rt_base_t offset;
	for(offset = 0; offset < RT_THREAD_PRIORITY_MAX;offset++)
	{
		rt_list_init(&rt_thread_priority_table[offset]);
	}
	rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
	rt_current_thread = RT_NULL;
	rt_thread_ready_priority_group = 0;

	/* 初始化线程休眠列表,当线程创建好没有启动之前会被放入到这个列表 */

}

6.2.3 修改线程初始化函数rt_thread_init()

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_object_init((rt_object_t)thread,RT_Object_Class_Thread,name);
	rt_list_init(&(thread->tlist));

	thread->entry = (void *)entry;
	thread->parameter = parameter;

	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;

	/* 初始化线程栈,并返回线程栈指针 */
	thread->sp = (void *)rt_hw_stack_init( thread->entry,
		                                   thread->parameter,
							               (void *)((char *)thread->stack_addr + thread->stack_size - 4) );
	**thread->init_priority = priority;
	thread->current_priority = priority;
	thread->number_mask = 0;
	thread->error = RT_EOK;
	thread->stat = RT_THREAD_INIT;**

}

6.2.4 添加线程启动函数rt_thread_startup()

rt_err_t rt_thread_startup(rt_thread_t thread)
{
	thread->current_priority = thread->init_priority;
	thread->number_mask = 1L << thread->current_priority;
	thread->stat = RT_THREAD_SUSPEND;
	rt_thread_resume(thread);
	if(rt_thread_self() != RT_NULL)
	{
		rt_schedule();
	}
}
rt_err_t rt_thread_resume(rt_thread_t thread)
{
	register rt_base_t temp;
	if((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
	{
		return -RT_ERROR;
	}
	temp = rt_hw_interrupt_disable();
	rt_list_remove(&(thread->tlist));

	rt_hw_interrupt_enable(temp);
	rt_schedule_insert_thread(thread);
}

6.2.5 修改空闲线程初始化函数rt_thread_idle_init()

void rt_thread_idle_init(void)
{
	    rt_thread_init(&idle,"idle",rt_thread_idle_entry,RT_NULL,&rt_thread_stack[0],sizeof(rt_thread_stack),RT_THREAD_PRIORITY_MAX - 1);

	**rt_thread_startup(&idle);**


}

6.2.6 修改启动系统调度器函数rt_system_scheduler_start()

不再是手动指定第一个需要运行的线程,而是根据优先级来决定第一个运行的线程。

void rt_system_scheduler_start(void)
{

	register struct rt_thread *to_thread;
	register rt_ubase_t highest_ready_priority;
	highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group)-1;
	P_DBG("first start pri %d\n",highest_ready_priority);
	to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);
	rt_current_thread = to_thread;
	rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

}

6.2.7 修改系统调度函数rt_schedule()

根据优先级来实现

void rt_schedule(void)
{

	register rt_base_t temp;
	rt_base_t level;
	register rt_ubase_t highest_ready_priority;
	struct rt_thread *to_thread;
	struct rt_thread *from_thread;
	temp = rt_hw_interrupt_disable();
	highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group)-1;
	P_DBG("read pri %d\n",highest_ready_priority);
	to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);
	P_DBG("read tgread %x\n",to_thread);
	if(to_thread != rt_current_thread)
	{
		P_DBG("!= current thread %x\n",rt_current_thread);
		rt_current_priority = (rt_uint8_t) highest_ready_priority;
		from_thread = rt_current_thread;
		rt_current_thread = to_thread;
		rt_hw_context_switch((rt_uint32_t)&from_thread->sp,(rt_uint32_t)&to_thread->sp);
		rt_hw_interrupt_enable(temp);
	}
	else
	{
		rt_hw_interrupt_enable(temp);
	}



	/* 产生上下文切换 */

}

6.2.8 修改线程阻塞函数


void rt_thread_delay(rt_tick_t tick)
{
	register rt_base_t temp;
	struct rt_thread *thread;
	temp = rt_hw_interrupt_disable(); 
	thread = rt_current_thread;
	thread->remaining_tick = tick;
	thread->stat = RT_THREAD_SUSPEND; 
	rt_thread_ready_priority_group &= ~thread->number_mask;
	rt_hw_interrupt_enable(temp);
	rt_schedule();
}

6.2.9 修改时基更i新函数rt_tick_increase()

void rt_tick_increase(void)
{
		rt_ubase_t i;
	struct rt_thread *thread;
	rt_tick++;
	for(i = 0;i < RT_THREAD_PRIORITY_MAX;i++)
	{
		thread = rt_list_entry(rt_thread_priority_table[i].next,struct rt_thread,tlist);
		if(thread->remaining_tick > 0)
		{
			thread->remaining_tick--;
			if(thread->remaining_tick == 0)
			{
				rt_thread_ready_priority_group |= thread->number_mask;
			}
		}
		rt_schedule();
	}
}

6.3 main.c


			/* 初始化线程 */
		rt_thread_init( &rt_flag1_thread,   "flag1",              /* 线程控制块 */
			                flag1_thread_entry,               /* 线程入口地址 */
			                RT_NULL,                          /* 线程形参 */
			                &rt_flag1_thread_stack[0],        /* 线程栈起始地址 */
			                sizeof(rt_flag1_thread_stack),3 );  /* 线程栈大小,单位为字节 */


			/* 将线程插入到就绪列表 */
		//rt_list_insert_before( &(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist) );
		P_DBG("thread flag1 %x timer %s\n",&rt_flag1_thread,rt_flag1_thread.thread_timer.parent.name);
		rt_thread_startup(&rt_flag1_thread);
			/* 初始化线程 */

		rt_thread_init( &rt_flag2_thread,           "falg2",      /* 线程控制块 */
			                flag2_thread_entry,               /* 线程入口地址 */
			                RT_NULL,                          /* 线程形参 */
			                &rt_flag2_thread_stack[0],        /* 线程栈起始地址 */
			                sizeof(rt_flag2_thread_stack),4 );  /* 线程栈大小,单位为字节 */

/* 将线程插入到就绪列表 */
		P_DBG("thread flag1 %x timer %s\n",&rt_flag2_thread,rt_flag2_thread.thread_timer.parent.name);

		//rt_list_insert_before( &(rt_thread_priority_table[1]),&(rt_flag2_thread.tlist) );
		rt_thread_startup(&rt_flag2_thread);
			/* 启动系统调度器 */
		rt_system_scheduler_start();


/* 线程1 */
void flag1_thread_entry( void *p_arg )
{
	for( ;; )
	{
		P_DBG("flag1 thread\n");

		flag2 = 1;
		P_DBG("flag1 thread will dela1\n");
		rt_thread_delay(10);
		flag2 = 0;
		P_DBG("flag1 thread will dela2\n");
		rt_thread_delay(10);

	}
}

/* 线程2 */
void flag2_thread_entry( void *p_arg )
{
	for( ;; )
	{
		P_DBG("flag2 thread\n");

		flag2 = 1;
		rt_thread_delay(2);
		flag2 = 0;
		P_DBG("flag2 thread will dela1\n");
		rt_thread_delay(2);

	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/135357.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spark算子

一、编写spark程序的准备工作&#xff08;程序入口 SparkContext&#xff09; 1.创建SparkConf val conf new SparkConf().setMaster("local[2]").setAppName("hello-app") 2.创建sparkContext val sc: SparkContext new SparkContext(conf) 二、基…

可视化 | echarts饼图改编

echarts模板来源 &#x1f4da;改编点 &#x1f407;基本样式 去掉legend、label&#xff1a;show: false背景透明&#xff1a;backgroundColor: "transparent"去除功能标签添加载入动态animationEasing: elasticOut, animationDelay: function (idx) {return Mat…

Python字符串字母大小写变换

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 说明&#xff1a; 字符串就是一系列字符&#xff0c;在Python中用引号括起来的都是字符串&#xff0c; 引号可以是单引号&#xff0c;也可以是双引号&#xff0…

基于猕猴感觉运动皮层的神经元Spike信号分析

公开数据集中文版详细描述参考前文&#xff1a;https://editor.csdn.net/md/?not_checkout1&spm1011.2124.3001.6192 目录 0. 公开数据集1. 神经元的raster和PSTH图1.1 Raster1.2 PSTH 2. 运动轨迹图 (center_out)3. 神经元的运动调制曲线 (tuning curve) 0. 公开数据集 …

区块链游戏,游戏开发

区块链游戏是一种基于区块链技术的新兴游戏类型&#xff0c;它具有去中心化、安全性高、透明度高、可追溯等特点。与传统的游戏开发相比&#xff0c;区块链游戏开发需要更多的技术和知识储备&#xff0c;同时也需要更加注重游戏本身的玩法和用户体验。 在区块链游戏中&#xff…

Java必刷入门递归题×5(内附详细递归解析图)

目录 1.求N的阶乘 2.求12...N的和 3.顺序打印数字的每一位 4.求数字的每一位之和 5.求斐波拉契数列 1.求N的阶乘 &#xff08;1&#xff09;解析题目意思 比如求5的阶乘&#xff0c;符号表示就是5&#xff01;&#xff1b;所以5&#xff01;5*4*3*2*1我们下面使用简单的…

ZDH-智能营销-执行流程解析

目录 项目源码 预览地址 安装包下载地址 通过2个方向解读ZDH流程图 图执行方向 数据流转方向 项目源码 zdh_web: GitHub - zhaoyachao/zdh_web: 大数据采集,抽取平台 zdh_magic_mirror: https://github.com/zhaoyachao/zdh_magic_mirror 预览地址 后台管理-登陆 用户…

C++套接字库sockpp介绍

sockpp是一个开源、简单、现代的C套接字库&#xff0c;地址为&#xff1a;https://github.com/fpagliughi/sockpp&#xff0c;最新发布版本为0.8.1&#xff0c;license为BSD-3-Clause。目前支持Linux、Windows、Mac上的IPv4、IPv6和Unix域套接字。其它*nix和POSIX系统只需很少的…

基于JavaWeb的网上体育商城的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

Docker容器编排

文章目录 基本概念Docker ComposeSwarm分布式NodeTaskservice集群搭建弹性伸缩 基本概念 针对容器生命周期的管理&#xff0c;对容器生命周期进行更方便更快捷的方式进行管理。 依赖管理&#xff1a;当一个容器必须在另一个容器运行完成后&#xff0c;才能运行时&#xff0c;…

【Windows Docker:安装nginx】

拉镜像 docker pull nginx运行初始镜像 docker run -d -p 80:80 --name nginx nginx拷贝文件 docker cp nginx:/etc/nginx/nginx.conf D:/dockerFile/nginx/nginx.conf docker cp nginx:/etc/nginx/conf.d D:/dockerFile/nginx/conf.d docker cp nginx:/usr/share/nginx/htm…

【蓝桥杯选拔赛真题18】C++病毒繁殖 第十二届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

目录 C/C++病毒繁殖 一、题目要求 1、编程实现 2、输入输出 二、算法分析 <

IDEA搭建ssm项目

此前&#xff0c;我一直在用eclipse编辑器做java项目&#xff0c;现在初次使用IDEA编辑器&#xff0c;在这里&#xff0c;我记录了使用IDEA环境下搭建ssm项目的过程。 创建Maven项目&#xff0c;如下 右击TEST4项目&#xff0c;在弹出的菜单中选择Add Framework Support 在弹出…

2023 年最新 Alipay 支付包商户接入实现 Java 网站在线支付功能(详细指南教程)

支付宝商户注册申请 若您的材料在电脑端&#xff0c;或企业/单位要求在电脑端操作。您的材料在手机端且方便在支付宝App中管理企业信息&#xff0c;可参阅《手机端开通企业支付宝-操作手册》开通企业支付宝。电脑端准备材料并使用个人支付宝扫码验证身份后开始注册。

基于STM32单片机抢答器设计

**单片机设计介绍&#xff0c; 基于STM32单片机抢答器设计-Proteus仿真 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于STM32单片机的抢答器设计可以用于教育和培训场景中的抢答游戏或考试环节。以下是一个基本的介绍设计步骤…

2023亚太杯数学建模A题B题C题思路代码分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

冯·诺伊曼体系结构--操作系统

文章目录 1.认识冯诺依曼系统1.1约翰冯诺依曼1.2冯诺依曼结构1.3存储器的读写速度1.4对冯诺依曼结构的认识1.5冯诺依曼结构在生活中的演示 2.操作系统--“搞管理”的软件2.1概念2.2OS存在的意义2.3管理的方式2.4系统调用和库函数概念 1.认识冯诺依曼系统 1.1约翰冯诺依曼 1.2冯…

Leetcode—69.x的平方根【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—69.x的平方根 直接法实现代码 int mySqrt(int x) {long long i 0;while(i * i < x) {i;}if(i * i > x) {return i - 1;}return i; }运行结果 二分法实现代码 int mySqrt(int x) {long long left 0, right (l…

Openlayers:自定义Controls

Openlayers是一款优秀的二维开源地图框架,支持矢量/栅格图层,支持移动端,并且易于自定义和拓展。下面来讲述一下自定义Control的基本思路。 openlayers-features 问题描述 最近在做个人项目时,遇到了一个小问题,就是在地图中心添加一个十字针形状的符号,用来表示地图中心…

Clickhouse学习笔记(12)—— 物化视图

ClickHouse 的物化视图是一种查询结果的持久化&#xff0c;与普通视图对比&#xff0c;其不仅保存了查询的逻辑&#xff0c;还保存了查询结果&#xff1b; 物化视图与普通视图的区别 普通视图不保存数据&#xff0c;保存的仅仅是查询语句&#xff0c;查询的时候还是从原表读取…