关于RT-Thread中优先级翻转问题的简记

2023-11-10

最近在学习RT-Thread的相关知识,记录一下心得。

优先级翻转

是指当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被低优先级线程持有,而这个低优先级线程在运行过程中可能又被其他一些中等优先级的线程抢占,从而造成高优先级线程被许多具有较低优先级的线程阻塞,实时性得到难以保证。
在这里插入图片描述

一句话来讲:高优先级线程等待资源的过程中,被其他较低优先级的线程抢占了,造成了低优先级线程“抢占”高优先级线程的现象。

引入互斥量

互斥量能够防止线程优先级翻转,方式如下:
通过使用互斥量,低优先级的C会和高优先级的A同等优先级,就不会被其他低于A但是高于原先C的中等优先级抢占。
在这里插入图片描述

引入代码

说明:代码来自官方

#include <rtthread.h>

/* 指向线程控制块的指针 */
static rt_thread_t tid1 = RT_NULL;
static rt_thread_t tid2 = RT_NULL;
static rt_thread_t tid3 = RT_NULL;
static rt_mutex_t mutex = RT_NULL;


#define THREAD_PRIORITY       10
#define THREAD_STACK_SIZE     512
#define THREAD_TIMESLICE      5

/* 线程 1 入口 */
static void thread1_entry(void *parameter)
{
	rt_kprintf("thread1_entry: the priority of thread1 is: %d\n", tid1->current_priority);
	
    /* 先让低优先级线程运行 */
    rt_thread_mdelay(100);

    /* 此时 thread3 持有 mutex,并且 thread2 等待持有 mutex */

    /* 检查 rt_kprintf("the producer generates a number: %d\n", array[set%MAXSEM]); 与 thread3 的优先级情况 */
    if (tid2->current_priority != tid3->current_priority)
    {
        /* 优先级不相同,测试失败 */
        rt_kprintf("thread1_entry: the priority of thread2 is: %d\n", tid2->current_priority);
        rt_kprintf("thread1_entry: the priority of thread3 is: %d\n", tid3->current_priority);
        rt_kprintf("thread1_entry: test failed.\n");
        return;
    }
    else
    {
        rt_kprintf("thread1_entry: the priority of thread2 is: %d\n", tid2->current_priority);
        rt_kprintf("thread1_entry: the priority of thread3 is: %d\n", tid3->current_priority);
        rt_kprintf("thread1_entry: test OK.\n");
    }
}

/* 线程 2 入口 */
static void thread2_entry(void *parameter)
{
    rt_err_t result;

    rt_kprintf("thread2_entry: the priority of thread2 is: %d\n", tid2->current_priority);

    /* 先让低优先级线程运行 */
    rt_thread_mdelay(50);


    /*
     * 试图持有互斥锁,此时 thread3 持有,应把 thread3 的优先级提升
     * 到 thread2 相同的优先级
     */
    result = rt_mutex_take(mutex, RT_WAITING_FOREVER);

    if (result == RT_EOK)
    {
        /* 释放互斥锁 */
        rt_mutex_release(mutex);
    }
}

/* 线程 3 入口 */
static void thread3_entry(void *parameter)
{
    rt_tick_t tick;
    rt_err_t result;

    rt_kprintf("thread3_entry: the priority of thread3 is: %d\n", tid3->current_priority);

    result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
    if (result != RT_EOK)
    {
        rt_kprintf("thread3_entry: thread3 take a mutex, failed.\n");
    }

    /* 做一个长时间的循环,500ms */
    tick = rt_tick_get();
    while (rt_tick_get() - tick < (RT_TICK_PER_SECOND / 2)) ;

    rt_mutex_release(mutex);
}

int pri_inversion(void)
{
    /* 创建互斥锁 */
    mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
    if (mutex == RT_NULL)
    {
        rt_kprintf("create dynamic mutex failed.\n");
        return -1;
    }

    /* 创建线程 1 高优先级 */
    tid1 = rt_thread_create("thread1",
                            thread1_entry, 
                            RT_NULL,
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY - 1,  //优先级是9
							THREAD_TIMESLICE);
    if (tid1 != RT_NULL)
         rt_thread_startup(tid1);
 
    /* 创建线程 2 中优先级 */
    tid2 = rt_thread_create("thread2",
                            thread2_entry, 
                            RT_NULL, 
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY,      //优先级是10
							THREAD_TIMESLICE);
    if (tid2 != RT_NULL)
        rt_thread_startup(tid2);

    /* 创建线程 3 低优先级 */
    tid3 = rt_thread_create("thread3",
                            thread3_entry, 
                            RT_NULL, 
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY + 1,  //优先级是11
							THREAD_TIMESLICE);
    if (tid3 != RT_NULL)
        rt_thread_startup(tid3);

    return 0;
}

简单分析

执行流程

  • 先创建三个线程
  • 先根据优先级输出每一个线程入口函数的第一句代码
  • 由于延时函数的存在,低优先级线程(3)先运行,得到互斥量,因为500s循环的存在,线程3不会结束
  • 中优先级线程(2)阻塞结束,比低优先级高,得到运行,也试图持有互斥量,此时会将线程3的优先级提高
  • 此时,线程1也阻塞结束,优先级最高,得到运行,输出线程2和线程3的优先级

调试结果

在这里插入图片描述

题外话:
今天有人事打电话要成绩单,看到以前的成绩方知“少壮不努力,老大徒伤悲”。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于RT-Thread中优先级翻转问题的简记 的相关文章

  • Qt的Tcp服务器多线程编程-附带代码展示

    Qt的Tcp服务器多线程编程 附带代码展示 该程序主要实现tcp服务器如何使用多线程的方式来连接多个客户端 此文章没有实现客户端的多线程编程 创建子线程时需要注意的点 1 子线程与主线程之间交互数据时 应采用信号槽的方式 2 子线程中实例化
  • java多线程中synchronized同步代码块执行问题

    在高洪岩老师的 java多线程编程核心技术 一书的用同步代码块解决同步方法的弊端一节中 p76页 有这样一句话 当一个线程访问object的一个synchronized同步代码块时 另一个线程依然可以访问该object对象中的非synchr
  • 静态代理模式

    package com kuang Demo04 静态代理总结 真实对象和代理对象都要实现同一个接口 代理对象要代理真实对象 好处 代理对象可以做很多真实对象做不了的事情 真实对象可以专注做自己的事情 public class Static
  • 对聊天室的优化&常用参数配置

    优化处1 编码和解码 编码解码用的是JDK 对象与数组的转换 这种虽然简单 但是效率不高 现在需要支持更多的序列化算法 就需要改进 抽取一个接口 Serializer 用以支持 序列化和 反序列化 package com zhao prot
  • 线程相关面试题

    1 ThreadPoolExecutor 线程池执行 有哪些常用的方法 1 执行线程池 submit excute 2 终止线程池 shutdown 3 判断线程是否终止 isShutdown 4 获取正在运行的线程数 getAcitive
  • JUC编程

    1 JUC JUC就是java util concurrent工具包的简称 这是一个处理线程的工具包 JDK 1 5开始出现的 1 传统的synchronized public class Synchronized public stati
  • 多线程实现事务回滚

    多线程实现事务回滚 特别说明CountDownLatch CountDownLatch的用法 CountDownLatch num 简单说明 主线程 mainThreadLatch await 和mainThreadLatch countD
  • java多线程使用教程

    文章目录 如何使用多线程 继承Thread类 实现Runnable接口 线程的生命周期 线程同步 线程间通信 shutdown 方法的重要性 如何使用多线程 在Java中 创建多线程的方式有两种 一种是继承Thread类 另一种是实现Run
  • Future 和 Callable

    一 Runnable 缺陷 不能返回一个返回值 不能抛出 checked Execption 二 Callable接口 类似于Runnable 被其他线程执行的任务 实现call方法 有返回值 三 Future的作用 Callable和Fu
  • Java多线程并行处理任务的实现

    Java多线程并行处理任务的实现 在实际项目开发的过程中 遇到过需要处理一个由多个子任务组成的任务的问题 顺序处理起来会造成响应时间超长 用户体验不好的问题 我想到一个解决方案 即使用多线程并行处理子任务 思路就是使用ThreadPoolE
  • 多线程太可怕了

    今天发现了一个多线程引起的bug 然后进一步体会到 这东西太容易出问题了 首先要说明的是 出问题的代码可不是一般人写的 是由一个叫EPAM systems的世界知名外包公司的人写的 这些java程序员个个经验丰富 心高气傲 貌似base在乌
  • GDB多线程调试常用命令

    gdb调试命令 step和next的区别 当前line有函数调用的时候 next会直接执行到下一句 step会进入函数 查看内存 gdb p a 打印变量地址 gdb x 0xbffff543 查看内存单元内变量 0xbffff543 0x
  • 条件变量(condition variable)详解

    原理 假设我们需要解决这样一个问题 一个列表记录需要处理的任务 一个线程往此列表添加任务 一个线程processTask处理此列表中的任务 这个问题的一个关键点在于processTask怎么判断任务列表不为空 一般有两种方法 一 proce
  • 主线程退出后,子线程会不会退出

    额 好吧 这是个标题党 其实所有的线程都是平级的 根本不存在主线程和子线程 下文所述为了方便 将在main函数中的线程看做主线程 其它线程看成子线程 特此说明 先考虑以下代码 include
  • C++-std::unique_lock介绍和简单使用

    unique lock std unique lock比std lock guard更灵活 这种灵活性主要体现在以下几点 lock guard在构造时或者构造前 std adopt lock 就已经获取互斥锁 并且在作用域内保持获取锁的状态
  • 多线程系列之——事件内核对象

    所有内核对象里面事件内核对象是最简单的一个 它包括一个使用计数 还有两个布尔值 一个布尔值用来表示事件是手动重置事件还是自动重置事件 另一个布尔值表示当前是否处于触发状态 当一个手动重置事件被触发的时候 所有等待该事件的线程都能变成调度状态
  • Linux系统编程:多线程交替打印ABC

    引言 分享关于线程的一道测试题 因为网上基本都是Java的解决方法 决定自己写一篇来记录一下线程的学习 问题描述 编写一个至少具有三个线程的程序 称之为线程 A B 和 C 其中线程 A 输出字符 A 线程 B 输出字符 B 线程 C 输出
  • JAVA实现简易HTTP服务器

    说实话 之前完全没有想过 我还能写出服务器 感觉服务器这么高端的东西 能会用就不错了 还能写 不吐槽了 开始了 这次的作业是搭建一个服务器 要能接收请求 并给浏览器返回正确响应 项目的下载地址 项目目标 实现一个简易的多线程服务器 可以处理
  • iOS线程初探(四) GCD 和 NSOperation 小结

    参考资料 关于iOS多线程 看我就够了 GCD 在GCD中 有两个概念很重要 那就是任务和队列 任务 其实就是你需要做的事情 一个Block而已 任务有两种执行方式 同步执行和异步执行 同步执行 会阻塞当前线程 直至该任务执行完成后当前线程
  • TaskDecatator用法

    在Spring框架中 TaskDecorator 是一个接口 它可以用来自定义由 ThreadPoolTaskExecutor 或其他任务执行器管理的任务的装饰行为 这通常用于在执行任务之前和之后添加某些上下文相关的行为 比如设置线程上下文

随机推荐

  • vite、vue3本地页面正常显示不刷新,外网穿透后页面不停刷新

    明明本地不会刷新 但映射到外网就会不停刷新页面 百度了一篇CSDN文章 vite项目 通过外网域名访问 无限刷新 的解决办法 没有解决我的问题 我使用的是natapp进行外网穿透 报错信息是 WebSocket connection to
  • C++ 生成随机数

    C 库有一个名为 rand 的函数 每次调用该函数都将返回一个非负整数 要使用 rand 函数 必须在程序中包含
  • 软件工程第一次阅读作业

    项目 内容 本作业属于北航软件工程课程 博客园班级链接 作业要求请点击链接查看 作业要求 我在这门课程的目标是 成为一个具有一定经验的软件开发人员 这个作业在哪个具体方面帮助我实现目标 让我对自己目前的状况有一个更加清醒的认识 1 快速阅读
  • 【华为OD统一考试A卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • jQuery如何判断input元素是否获得焦点(点击编辑时)

    问题提出 如果你要判断input元素是否获得焦点 或者是否处在活动编辑状态 使用jQuery的 hasFocus 方法或 is focus 方法貌似都无效 搜索网上给出的办法 几乎净是采用上述处理方法 然并卵 都是扯淡 我的解决办法 监听点
  • Caffe中对MNIST执行train操作执行流程解析

    之前在 http blog csdn net fengbingchun article details 49849225 中简单介绍过使用Caffe train MNIST的文章 当时只是仿照caffe中的example实现了下 下面说一下
  • Windows下VVC参考软件VTM10.0编译和运行

    1 预备工作 VTM软件下载 链接https vcgit hhi fraunhofer de jvet VVCSoftware VTM tree masterhttps vcgit hhi fraunhofer de jvet VVCSof
  • Word中批量更新域的两个小方法

    一处域更新 如果只有一处需要更新 对着域右键选择 更新域 即可 多处域更新 很多需要更新的时候 可以如下操作 两种方法应该都可以 选择 打印预览 可以更新文档中的所有域 MOS认证的老师教的 CTRL A 全选 然后F9 更新 即可 自己觉
  • UE4 虚幻引擎,绑定Mesh到Skeleton骨骼插槽Socket

    1 在Skeleton骨骼中Add socket添加插槽 新建的Slot socket插槽 可以添加Preview Asset预览资产 方便查看 2 将Component组件绑定到骨骼中 新建一个StaticMesh 绑定组件到骨骼插槽 3
  • 如何学习C++

    转自 http blog csdn net yong2016 article details 9321837 看了这篇文章才知道自己最近太浮躁了 学做技术也是学做人 读者定位是两类人群 a 初学者 即将入手 C 语言 不知道如何开始 b 已
  • Tomcat 与 Nginx,Apache的区别

    Apache指的应该是Apache软件基金会下的一个项目 Apache HTTP Server Project Nginx同样也是一款开源的HTTP服务器软件 当然它也可以作为邮件代理服务器 通用的TCP代理服务器 Tomcat是Apach
  • 计算机分析学生表字段,巧用Excel数据透视表统计分析学生成绩

    巧用Excel数据透视表统计分析学生成绩 科技信息 IT论坛 SCIENCE TECHNOLOGYINFORMATION2010年第19期 巧用Excel数据透视表统计分析学生成绩 魏零 桂林航天工业高等专科学校计算机系 广西 桂林 541
  • Coverless Image Steganography Based on Generative Adversarial Network

    基于生成对抗网络的无载体图像隐写技术 摘要 传统图像隐写技术 修改 嵌入到载体图像来传输秘密信息 gt 隐写工具很容易检测到载体图像的失真 gt 秘密信息的泄露 无载体图像隐写技术 不修改载体图像就可以隐藏秘密信息 但存在容量低 质量差等问
  • 操作系统地址重定位相关练习题

    一 问题描述 某虚拟存储器的用户空间共有32个页面 每页1KB 主存16KB 假定某时刻系统为用户的第0 1 2 3页分配的物理块号为5 10 4 7 而该用户作业的长度为6页 试将十六进制的虚拟地址0A5C 103C转换成物理地址 二 正
  • ★【动态规划】【线段树】基站选址

    问题描述 有N个村庄坐落在一条直线上 第i i gt 1 个村庄距离第1个村庄的距离为Di 需要在这些村庄中建立不超过K个通讯基站 在第i个村庄建立基站的费用为Ci 如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站 那么就成它被覆盖
  • 华为od机考题目-IPv4地址转换成为整数

    while 1 try nums list map int input split if len nums 4 有效ip 为 4段
  • Leetcode No. 136. Single Number

    Given an array of integers every element appears twice except for one Find that single one Note Your algorithm should ha
  • 面试官:你对Kafka了解吗?这41个问题你能答出几个

    一 请说明什么是Apache Kafka Apache Kafka是由Apache开发的一种发布订阅消息系统 它是一个分布式的 分区的和重复的日志服务 二 请说明什么是传统的消息传递方法 传统的消息传递方法包括两种 排队 在队列中 一组用户
  • 微信小程序真机调试实现获取本地服务器数据

    一般来说 如果不涉及到后端数据 我们通过微信小成开发工具预览功能是可以直观看到项目的情况的 但是一旦涉及到后端本地服务器数据 预览是无法获取到的 而真机调试得按下面操作才能实现 通过win r 打开命令行工具 输入ipconfig 如果你是
  • 关于RT-Thread中优先级翻转问题的简记

    最近在学习RT Thread的相关知识 记录一下心得 优先级翻转 是指当一个高优先级线程试图通过信号量机制访问共享资源时 如果该信号量已被低优先级线程持有 而这个低优先级线程在运行过程中可能又被其他一些中等优先级的线程抢占 从而造成高优先级