IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> [006] [RT-Thread学习笔记] 互斥量详解与应用 -> 正文阅读

[JavaScript知识库][006] [RT-Thread学习笔记] 互斥量详解与应用

RT-Thread
学习笔记
互斥量概念
互斥量与信
号量的区别
自旋锁与互
斥锁的区别
优先级翻转问题
及其解决方法
互斥量控制块
互斥量函数接口
创建/删除
初始化/脱离
获取/无等待获取
释放互斥量
互斥量应用示例
互斥访问临
界资源实验
优先级继承特性实验
总结

RT-Thread版本:4.0.5
MCU型号:STM32F103RCT6(ARM Cortex-M3 内核)

1 互斥量概念

互斥量又名互斥锁、互斥型信号量,是一种特殊的二值信号量。
任意时刻互斥量的状态只有两种:

  • 闭锁:互斥量被某线程持有,有且仅有该线程可以获得互斥量的所有权。
  • 开锁:互斥量被该线程释放,同时该线程也失去了对此互斥量的所有权。

1.1 互斥量与信号量的区别

  1. 互斥量的线程拥有互斥量的所有权,互斥量只能由持有线程释放,信号量可以由任何线程释放;
  2. 互斥量支持递归访问且能防止线程优先级翻转,而信号量不可以;
  3. 二值信号量适用于实现同步(线程之间、线程与中断之间),互斥量也可以用于同步,但更多用于临界区资源的保护(即互斥)。
  4. 互斥量值只能为0/1,信号量值一般为0-65535

1.2 自旋锁与互斥锁的区别

RT-Thread内核目前还没有自旋锁(spin lock)

自旋锁与互斥锁(量)类似,都是用于互斥操作临界资源,任何时刻仅能有一个执行单元(线程、中断)可以获得锁。两者在调度机制上有所不同:

  • 对于互斥锁(sleep-waiting类型),若资源已被占用,资源申请者只能进入睡眠状态。
  • 对于自旋锁(busy-waiting类型),不会让调用者睡眠,若自旋锁被别的执行单元保持,调用者会一直循环检测该自旋锁的保持者是否已释放了锁(相当于死循环检测标志位)。

综上可知,互斥锁的调用者在调用过程中会发生上下文切换(挂起态与运行态的转换),初始时间开销大;而自旋锁的调用者一直处于运行态,虽初始开销低于互斥锁,但会长期占用CPU资源。基于上述特点,它们有不同的应用场合

  • 互斥锁适用于临界区持锁时间比较的操作,即临界区代码时间复杂度高或,因此只能在线程上下文中使用。
  • 自旋锁适用于锁使用者保持锁时间比较的情况,此时其效率远高于互斥锁,因此可以在任何上下文中使用。

注意

  • 自旋锁只有在内核可抢占式或SMP(多核处理器)的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。
  • 互斥锁支持递归访问,而自旋锁不支持,当自旋锁的持有者试图再次获取该自旋锁时,会造成死锁,导致自身和其他申请该锁的线程不停地疯狂“自旋”,无法获取资源,陷入死循环。

此外,由于自旋锁的调用者不会进入睡眠态,因此就没有优先级翻转的问题。

2 优先级翻转问题及其解决方法

  • 优先级翻转
    信号量详解及应用一文中提到使用信号量会出现优先级翻转问题,具体原因如下:当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被一低优先级线程持有,而这个低优先级线程在运行过程中可能又被其它一些中等优先级的线程抢占,因此造成高优先级线程被许多具有较低优先级的线程阻塞,实时性难以得到保证。

解决优先级翻转方法

  • 优先级继承
    提高某个占有某种资源的低优先级线程的优先级,使之与所有等待该资源的线程中优先级最高的那个线程的优先级相等,然后执行,而当这个低优先级线程释放该资源时,优先级重新回到初始设定。因此,继承优先级的线程避免了系统资源被任何中间优先级的线程抢占。
  • 优先级天花板
    直接将某个占有某种资源的低优先级线程的优先级,提升至当前系统所有线程中最高优先级的线程的优先级,该最高优先级即为优先级天花板。等该线程释放资源后,优先级重新回到初始设定。

两者区别:优先级继承只有当高优先级线程访问被已低优先级线程占用的临界资源时,才会提高低优先级线程的优先级,而优先级天花板是谁先占用资源,就将该线程优先级提升到当前系统最高优先级。

RT-Thread中互斥量采用优先级继承算法,以解决优先级翻转问题。所以对于临界资源的保护一般建议使用互斥量。

注意:获取互斥量后要尽快释放,并且在持有互斥量过程中,不得再更改持有互斥量线程的优先级,否则可能会人为造成优先级翻转的问题。

3 互斥量控制块

struct rt_mutex
{
    struct rt_ipc_object parent;                /* 继承自 ipc_object 类 */

    rt_uint16_t          value;                   /* 互斥量的值 */
    rt_uint8_t           original_priority;     /* 持有线程的原始优先级 */
    rt_uint8_t           hold;                     /* 持有线程的持有次数   */
    struct rt_thread    *owner;                 /* 当前拥有互斥量的线程 */
};
/* rt_mutext_t 为指向互斥量结构体的指针类型  */
typedef struct rt_mutex* rt_mutex_t;
  • value:初始状态下互斥量的值为 1,因此,如果值大于 0,表示可以使用互斥量。
  • original_priority:用来保存优先级继承时持有线程的原优先级
  • hold:用于记录线程递归调用获取互斥量的次数
  • owner:保存当前持有该互斥量线程的地址

4 互斥量函数接口

在这里插入图片描述

4.1 创建/删除

  • 创建互斥量
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
{
    struct rt_mutex *mutex;
    (void)flag;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* 动态分配互斥量对象 */
    mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
    if (mutex == RT_NULL)
        return mutex;

    /* 初始化ipc对象 */
    _ipc_object_init(&(mutex->parent));

    mutex->value              = 1;
    mutex->owner              = RT_NULL;
    mutex->original_priority  = 0xFF;
    mutex->hold               = 0;

    /* flag 仅能使用RT_IPC_FLAG_PRIO. RT_IPC_FLAG_FIFO不能解决无界优先级翻转问题 */
    mutex->parent.parent.flag = RT_IPC_FLAG_PRIO;

    return mutex;
}

互斥量的flag标志目前已经作废,仅能使用RT_IPC_FLAG_PRIO

  • 删除互斥量
rt_err_t rt_mutex_delete(rt_mutex_t mutex)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* 参数检查 */
    RT_ASSERT(mutex != RT_NULL);
    RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
    RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent) == RT_FALSE);

    /* 唤醒所有挂在该互斥量等待列表上的线程 */
    _ipc_list_resume_all(&(mutex->parent.suspend_thread));

    /* 删除互斥量对象 */
    rt_object_delete(&(mutex->parent.parent));

    return RT_EOK;
}

当删除互斥量时,所有等待此互斥量的线程都将被唤醒,返回值为-RT_ERROR,然后系统再将该互斥量从内核对象管理器链表中删除并释放内存。

4.2 初始化/脱离

静态初始化与脱离(静态对象不能被删除)互斥量对象,功能与上述函数一致,不再赘述。

4.3 获取/无等待获取

  • 获取互斥量
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* 即使time = 0, 这个函数也不能在中断中使用 */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* parameter check */
    RT_ASSERT(mutex != RT_NULL);
    RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);

    /* 获取当前调用rt_mutex_take函数线程的地址 */
    thread = rt_thread_self();

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

    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent)));

    /* 设置线程错误码 */
    thread->error = RT_EOK;

    if (mutex->owner == thread)
    {
        if(mutex->hold < RT_MUTEX_HOLD_MAX)     // RT_MUTEX_HOLD_MAX == 0xff
        {
            /* 若是同一个线程(即当前调用函数的线程为持有该互斥量的线程) */
            mutex->hold ++;
        }
        else
        {
            rt_hw_interrupt_enable(temp); /* enable interrupt */
            return -RT_EFULL; /* 参数溢出 */
        }
    }
    else
    {
__again:
        /* 初始状态下互斥量值为1, 因此如果该值大于0, 则表示可以使用互斥量 */
        if (mutex->value > 0)
        {
            /* 互斥量可用 */
            mutex->value --;

            /* 记录该互斥量对象持有线程的地址及其原有优先级 */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;
            if(mutex->hold < RT_MUTEX_HOLD_MAX)
            {
                mutex->hold ++;
            }
            else
            {
                rt_hw_interrupt_enable(temp); /* enable interrupt */
                return -RT_EFULL; /* value overflowed */
            }
        }
        else
        {
            /* 不等待则直接返回超时错误码 */
            if (time == 0)
            {
                /* set error as timeout */
                thread->error = -RT_ETIMEOUT;

                /* enable interrupt */
                rt_hw_interrupt_enable(temp);

                return -RT_ETIMEOUT;
            }
            else
            {
                /* 互斥量不可用,将当前线程压入挂起链表 */
                RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
                                            thread->name));

                /* 判断申请占用该互斥量线程与持有互斥量线程的优先级大小关系(注意: 越小代表优先级越高) */
                if (thread->current_priority < mutex->owner->current_priority)
                {
                    /* 改变持有互斥量线程的优先级 */
                    rt_thread_control(mutex->owner,
                                      RT_THREAD_CTRL_CHANGE_PRIORITY,
                                      &thread->current_priority);
                }

                /* 挂起当前线程 */
                _ipc_list_suspend(&(mutex->parent.suspend_thread),
                                    thread,
                                    mutex->parent.parent.flag);

                /* 若有等待时间,则开始计时*/
                if (time > 0)
                {
                    RT_DEBUG_LOG(RT_DEBUG_IPC,
                                 ("mutex_take: start the timer of thread:%s\n",
                                  thread->name));

                    /* 重置线程定时器的超时时间并启动它 */
                    rt_timer_control(&(thread->thread_timer),
                                     RT_TIMER_CTRL_SET_TIME,
                                     &time);
                    rt_timer_start(&(thread->thread_timer));
                }

                /* enable interrupt */
                rt_hw_interrupt_enable(temp);

                /* 发起线程调度 */
                rt_schedule();

                if (thread->error != RT_EOK)
                {
                    /* 被信号量打断,再试一次 */
                    if (thread->error == -RT_EINTR) goto __again;

                    /* return error */
                    return thread->error;
                }
                else  /* 成功获取信号量 */
                {                   
                    /* 关中断 */
                    temp = rt_hw_interrupt_disable();
                }
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent)));

    return RT_EOK;
}
  • 若互斥量已被当前线程占用,互斥量持有计数值mutex->hold加1,且当前线程不会挂起等待;

  • 若互斥量未被其他线程占用,则被当前申请互斥量的线程成功获取,互斥量值mutex->value从1->0,并记录该线程的地址及其原优先级,而后将mutex->hold从0->1;

  • 若互斥量已被其他线程占用,即mutex->value为0,则当前线程挂起等待,此时:

    • time==0:直接返回超时错误码
    • time>0:优先级继承算法在此体现:首先判断申请获取该互斥量线程与持有互斥量线程的当前优先级大小关系,如果申请线程优先级thread->current_priority 高于 持有线程优先级mutex->owner->current_priority,则将持有线程的优先级提高至申请线程的优先级。
      然后挂起当前线程,设置它的定时器超时时间并启动定时器,最后发起任务调度。
  • 无等待获取互斥量

rt_err_t rt_mutex_trytake(rt_mutex_t mutex)
{
    return rt_mutex_take(mutex, RT_WAITING_NO);
}

rt_mutex_take(rt_mutex_t mutex, 0)

4.4 释放互斥量

rt_err_t rt_mutex_release(rt_mutex_t mutex)
{
    register rt_base_t temp;
    struct rt_thread *thread;
    rt_bool_t need_schedule;

    /* parameter check */
    RT_ASSERT(mutex != RT_NULL);
    RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);

    need_schedule = RT_FALSE;

    /* 只有在线程上下文中才能释放互斥锁,因为需要判断互斥锁的持有线程。 */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* 获取当前线程 */
    thread = rt_thread_self();

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


    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent)));

    /* 互斥量仅能被持有者释放 */
    if (thread != mutex->owner)
    {
        thread->error = -RT_ERROR;

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        return -RT_ERROR;
    }

    /* 互斥量持有值-1 */
    mutex->hold --;
    /* 如果持有值为0 */
    if (mutex->hold == 0)
    {
        /* 将持有线程改为原先优先级 */
        if (mutex->original_priority != mutex->owner->current_priority)
        {
            rt_thread_control(mutex->owner,
                              RT_THREAD_CTRL_CHANGE_PRIORITY,
                              &(mutex->original_priority));
        }

        /* 唤醒阻塞线程 */
        if (!rt_list_isempty(&mutex->parent.suspend_thread))
        {
            /* 获取阻塞线程 */
            thread = rt_list_entry(mutex->parent.suspend_thread.next,
                                   struct rt_thread,
                                   tlist);

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n",
                                        thread->name));

            /* 设置互斥量的持有线程为当前线程,并保存其原优先级 */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;

            if(mutex->hold < RT_MUTEX_HOLD_MAX)
            {
                mutex->hold ++;
            }
            else
            {
                rt_hw_interrupt_enable(temp); /* enable interrupt */
                return -RT_EFULL; /* value overflowed */
            }

            /* 唤醒线程 */
            _ipc_list_resume(&(mutex->parent.suspend_thread));

            need_schedule = RT_TRUE;
        }
        else
        {
            if(mutex->value < RT_MUTEX_VALUE_MAX)
            {
                /* increase value */
                mutex->value ++;
            }
            else
            {
                rt_hw_interrupt_enable(temp); /* enable interrupt */
                return -RT_EFULL; /* value overflowed */
            }

            /* 清除互斥量信息 */
            mutex->owner             = RT_NULL;
            mutex->original_priority = 0xff;
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* 执行一次任务调度 */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}

若调用释放互斥量函数的线程不是持有该互斥量的线程,直接返回-RT_ERROR;若是则将mutex->hold减1,当mutex->hold减到0时:

  • 判断互斥量对象中保存的持有线程的原优先级与其当前优先级是否一致(即是否发生优先级继承),若一致则将持有线程的优先级恢复至其原优先级。
  • 判断该互斥量等待队列上是否有挂起的线程,若有则将互斥量对象的持有线程切换至等待队列上的第一个线程(按优先级排序),并保存其原优先级,然后让mutex->hold从0->1,最后唤醒该线程,发生一次任务调度;若没有直接让mutex->value从0->1,然后清空该互斥量对象信息(持有线程清为RT_NULL,保存优先级设为0xff)。

5 互斥量应用示例

5.1 互斥访问临界资源实验

/*
 * Date           Author   
 * 2022-02-06     issac wan
 */

#include <rtthread.h>

#define my_printf(fmt, ...)         rt_kprintf("[%u]"fmt"\n", rt_tick_get(), ##__VA_ARGS__)

#define THREAD_PRIORITY         20
#define THREAD_TIMESLICE        5

static uint16_t num1 = 0, num2 = 0;
static rt_mutex_t  mutex = RT_NULL;
static rt_thread_t thread1 = RT_NULL;
static rt_thread_t thread2 = RT_NULL;

void thread_entry1(void* param){
    while (1){
        rt_mutex_take(mutex, RT_WAITING_FOREVER);
        num1++;
        rt_thread_delay(10);
        num2++;
        rt_mutex_release(mutex);
    }
}

void thread_entry2(void* param){
    while (1){
        rt_mutex_take(mutex, RT_WAITING_FOREVER);
        if (num1 == num2)
            my_printf("Successful! num1:[%d], num2:[%d]", num1, num2);
        else
            my_printf("Fail! num1:[%d], num2:[%d]", num1, num2);
        num1++;
        num2++;
        rt_thread_delay(1);
        rt_mutex_release(mutex);

        if (num1 > 50)
            return;
    }
}

int mutex_sample(void){
    mutex = rt_mutex_create("mutex", RT_IPC_FLAG_PRIO);
    if (mutex == RT_NULL)
        return -RT_ERROR;

    thread1 = rt_thread_create("thread1",
                                thread_entry1,
                                RT_NULL,
                                512,
                                THREAD_PRIORITY,
                                THREAD_TIMESLICE);
    if (thread1 == RT_NULL)
        return -RT_ERROR;
    else
        rt_thread_startup(thread1);


    thread2 = rt_thread_create("thread2",
                                thread_entry2,
                                RT_NULL,
                                512,
                                THREAD_PRIORITY-1,
                                THREAD_TIMESLICE);
    if (thread2 == RT_NULL)
        return -RT_ERROR;
    else
        rt_thread_startup(thread2);

    return RT_EOK;
}
INIT_APP_EXPORT(mutex_sample);
  • 创建一个互斥量,用于保护临界资源num1和num2,使各线程互斥访问该临界资源。
  • 创建两个线程:线程1和线程2,线程2优先级高于线程1。线程1对两数分别进行加1操作;线程2中会判断两数是否相等,相等则表示互斥量保护临界资源成功,然后再对两数进行加1操作。

本实验引用官方例程,但官方没有在线程2的入口函数中加延时,关于是否应加延时在此做个讨论。

  • 若不加延时,则线程2一直处于运行态,而线程1优先级比其低,因此无法抢占CPU资源,不会执行获取互斥量的操作,也就不能将线程1挂在互斥量等待队列中。所以当线程2执行时,互斥量等待队列为空,直接让mutex->value加1,然后清空互斥量,恢复初始开锁状态,线程2可再次获取该互斥量,以此循环直至num加到50,系统回收线程2后,线程1才能抢占到CPU资源,执行其入口函数。
    串口打印信息如下:
    在这里插入图片描述
    结果与官方一致,但实际上线程1在线程2回收后才开始执行,保护了个寂寞

  • 若加延时,会挂起线程2一段时间,线程1得以抢占到CPU资源,若获取互斥量失败,则将其挂在互斥量等待队列上,当线程2休眠结束后,执行开锁操作时,系统会将互斥量持有线程切换到线程1,然后发起一次任务调度(因当前运行的线程2其优先级最高,所以还是会继续执行线程2,直到它执行获取互斥量操作时,因获取失败而被挂起,此时才会切换到线程1)。
    串口打印信息如下:
    在这里插入图片描述
    使用互斥量保护临界资源num1和num2成功。

5.2 优先级继承特性实验

/*
 * Date           Author   
 * 2022-02-06     issac wan
 */

#include <rtthread.h>

#define my_printf(fmt, ...)         rt_kprintf("[%u]"fmt"\n", rt_tick_get(), ##__VA_ARGS__)

#define THREAD_STACK_SIZE     512
#define THREAD_PRIORITY       20
#define THREAD_TIMESLICE      5

static rt_mutex_t  mutex = RT_NULL;
static rt_thread_t thread1 = RT_NULL;
static rt_thread_t thread2 = RT_NULL;

static void thread_entry1(void* param){
    while (1){
        /* 先让低优先级线程运行 */
        rt_thread_mdelay(50);

        /* 试图持有互斥锁,此时线程2持有,应把线程2的优先级提升到线程1相同的优先级 */
        rt_mutex_take(mutex, RT_WAITING_FOREVER);

        return;
    }
}

static void thread_entry2(void* param){
    while (1){
        my_printf("优先级继承实验开始!");
        rt_mutex_take(mutex, RT_WAITING_FOREVER);
        my_printf("继承前的优先级:");
        my_printf("the priority of thread1 is: %d", thread1->current_priority);
        my_printf("the priority of thread2 is: %d", thread2->current_priority);

        /* 等待线程1获取互斥量 */
        rt_thread_mdelay(100);

        my_printf("继承后的优先级:");
        if (thread1->current_priority != thread2->current_priority){
            my_printf("the priority of thread1 is: %d", thread1->current_priority);
            my_printf("the priority of thread2 is: %d", thread2->current_priority);
            my_printf("测试失败!");
        }else{
            my_printf("the priority of thread1 is: %d", thread1->current_priority);
            my_printf("the priority of thread2 is: %d", thread2->current_priority);
            my_printf("测试成功!");
        }

        rt_mutex_release(mutex);
        my_printf("恢复原优先级:");
        my_printf("the priority of thread1 is: %d", thread1->current_priority);
        my_printf("the priority of thread2 is: %d", thread2->current_priority);

        my_printf("优先级继承实验结束!");
        return;
    }
}

int mutex_sample(void){
    mutex = rt_mutex_create("mutex", RT_IPC_FLAG_PRIO);
    if (mutex == RT_NULL)
        return -RT_ERROR;

    thread1 = rt_thread_create("thread1",
                                thread_entry1,
                                RT_NULL,
                                THREAD_STACK_SIZE,
                                THREAD_PRIORITY - 1,
                                THREAD_TIMESLICE);
    if (thread1 == RT_NULL)
        return -RT_ERROR;
    else
        rt_thread_startup(thread1);


    thread2 = rt_thread_create("thread2",
                                thread_entry2,
                                RT_NULL,
                                THREAD_STACK_SIZE,
                                THREAD_PRIORITY,
                                THREAD_TIMESLICE);
    if (thread2 == RT_NULL)
        return -RT_ERROR;
    else
        rt_thread_startup(thread2);

    return RT_EOK;
}
INIT_APP_EXPORT(mutex_sample);
  • 首先,创建两个线程:线程1与线程2,线程1的优先级高于线程2;
  • 先让线程1执行50ms延时,让线程2先成功获取互斥量,然后打印出优先级继承前的两线程优先级(主要看线程2的优先级,线程1不会发生优先级继承),再延时100ms,等待线程1获取互斥量;
  • 当线程1获取互斥量时,因其已被线程2持有,获取失败,由于线程1优先级高于线程2,所以发生优先级继承,将线程2的优先级调整到等待线程优先级中最高的优先级(即线程1的优先级);
  • 线程2延时结束后,会打印继承后的优先级,然后释放互斥量,因线程2发生了优先级继承,所以释放时会将其优先级改为原优先级,最后打印恢复后的优先级。

串口打印信息如下:
在这里插入图片描述
可以看到线程2继承前的优先级为20,继承后优先级提升至线程1的优先级19,在成功释放互斥量后恢复原优先级20。

6 总结

本文主要介绍了互斥量的特性,以及它与信号量、自旋锁的区别,然后阐述了优先级翻转问题带来的危害与解决方法,RT-Thread利用互斥量的优先级继承特性来解决该问题。其次详细分析了RT-Thread中互斥量控制块与其常用函数接口的原理与使用方法,最后通过两个实验来测试互斥量的两个常用使用场合:互斥保护临界区资源和多线程同步引发的优先级翻转问题。

END

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:38:22  更:2022-02-07 13:41:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:36:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码