首页 > 其他分享 >rtthread_互斥量

rtthread_互斥量

时间:2023-07-15 18:34:47浏览次数:31  
标签:rt RT parent thread rtthread 互斥 mutex owner

1 互斥量

  互斥量即互相排斥的信号量,是一种特殊的二值信号量;只能由持有线程释放,而信号量则可以由任何线程释放;

  拥有互斥量的线程拥有互斥量的所有权,互斥量支持递归访问且能防止多线程优先级翻转;

  1.1 线程优先级翻转问题

    互斥量通过继承线程优先级,将持有互斥量的线程优先级提高到和挂载到suspend_thread的线程优先级一样高,这样就不会有低优先级的线程反而先被调度执行了;

2 mutex 结构体

//rtdef.h   
#ifdef RT_USING_MUTEX
struct rt_mutex
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */
    rt_uint16_t          value;                         /**< value of mutex */
    rt_uint8_t           original_priority;             /**< priority of last thread hold the mutex */
    rt_uint8_t           hold;                          /**< numbers of thread hold the mutex */
    struct rt_thread    *owner;                         /**< current owner of mutex */
};
typedef struct rt_mutex *rt_mutex_t;
#endif

3 mutex 使用函数

  3.1 rt_mutex_create 分配结构体并初始化

//ipc.c       
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
{
    struct rt_mutex *mutex;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object */
    mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name);
    if (mutex == RT_NULL)
        return mutex;

    /* init ipc object */
    rt_ipc_object_init(&(mutex->parent));

    mutex->value              = 1;              //因为是互斥的,所以只有1;
    mutex->owner              = RT_NULL;
    mutex->original_priority  = 0xFF;
    mutex->hold               = 0;

    /* set flag */
    mutex->parent.parent.flag = flag;           //初始化成了RT_IPC_FLAG_PRIO,可以优先级继承;

    return mutex;
}
RTM_EXPORT(rt_mutex_create);

  3.2 rt_mutex_take 获取互斥量

// ipc.c     要是递归访问,就hold++;
//           if互斥锁未上锁,那就给当前线程上锁;else根据time判断是否需要suspend_thread等待解锁;
//           在suspend_thread线程的时候,如果suspend_thread的优先级比较高,就把拥有锁的线程优先级提高到一样高,等解锁的时候再改回来;
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* this function must not be used in interrupt even if time = 0 */
    RT_DEBUG_IN_THREAD_CONTEXT;

    RT_ASSERT(mutex != RT_NULL);

    /* get current thread */
    thread = rt_thread_self();

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

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

    RT_DEBUG_LOG(RT_DEBUG_IPC,
                 ("mutex_take: current thread %s, mutex value: %d, hold: %d\n",
                  thread->name, mutex->value, mutex->hold));

    /* reset thread error */
    thread->error = RT_EOK;

    if (mutex->owner == thread)
    {
        /* it's the same thread 这就是所说的支持"递归访问",要是递归加锁,就hold++;*/
        mutex->hold ++;
    }
    else
    {
__again:
        /* The value of mutex is 1 in initial status. Therefore, if the
         * value is great than 0, it indicates the mutex is avaible.
         */
        if (mutex->value > 0)
        {
            /* mutex is available */
            mutex->value --;

            /* set mutex owner and original priority */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold ++;
        }
        else
        {
            /* no waiting, return with timeout */
            if (time == 0)
            {
                /* set error as timeout */
                thread->error = -RT_ETIMEOUT;

                /* enable interrupt */
                rt_hw_interrupt_enable(temp);

                return -RT_ETIMEOUT;
            }
            else
            {
                /* mutex is unavailable, push to suspend list */
                RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n",
                                            thread->name));

                /* change the owner thread priority of mutex */
                if (thread->current_priority < mutex->owner->current_priority)
                {
                    /* change the owner thread priority */
                    rt_thread_control(mutex->owner,
                                      RT_THREAD_CTRL_CHANGE_PRIORITY,
                                      &thread->current_priority);
                }

                /* suspend current thread */
                rt_ipc_list_suspend(&(mutex->parent.suspend_thread),
                                    thread,
                                    mutex->parent.parent.flag);

                /* has waiting time, start thread timer */
                if (time > 0)
                {
                    RT_DEBUG_LOG(RT_DEBUG_IPC,
                                 ("mutex_take: start the timer of thread:%s\n",
                                  thread->name));

                    /* reset the timeout of thread timer and start it */
                    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);

                /* do schedule */
                rt_schedule();

                if (thread->error != RT_EOK)
                {
                	/* interrupt by signal, try it again */
                	if (thread->error == -RT_EINTR) goto __again;

                    /* return error */
                    return thread->error;
                }
                else
                {
                    /* the mutex is taken successfully. */
                    /* disable interrupt */
                    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;
}
RTM_EXPORT(rt_mutex_take);

  3.3 rt_mutex_release 释放互斥量

//ipc.c 
//if解锁线程不是拥有互斥锁的线程,那么返回错误;
//线程解锁后,如果优先级被调高了则调回来,如果有suspend_thread,那么就把互斥锁给suspend_thread使用;
rt_err_t rt_mutex_release(rt_mutex_t mutex)
{
    register rt_base_t temp;
    struct rt_thread *thread;
    rt_bool_t need_schedule;

    need_schedule = RT_FALSE;

    /* only thread could release mutex because we need test the ownership */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* get current thread */
    thread = rt_thread_self();

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

    RT_DEBUG_LOG(RT_DEBUG_IPC,
                 ("mutex_release:current thread %s, mutex value: %d, hold: %d\n",
                  thread->name, mutex->value, mutex->hold));

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

    /* mutex only can be released by owner */
    if (thread != mutex->owner)
    {
        thread->error = -RT_ERROR;

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);

        return -RT_ERROR;
    }

    /* decrease hold */
    mutex->hold --;
    /* if no hold */
    if (mutex->hold == 0)
    {
        /* change the owner thread to original priority */
        if (mutex->original_priority != mutex->owner->current_priority)
        {
            rt_thread_control(mutex->owner,
                              RT_THREAD_CTRL_CHANGE_PRIORITY,
                              &(mutex->original_priority));
        }

        /* wakeup suspended thread */
        if (!rt_list_isempty(&mutex->parent.suspend_thread))
        {
            /* get suspended 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));

            /* set new owner and priority */
            mutex->owner             = thread;
            mutex->original_priority = thread->current_priority;
            mutex->hold ++;

            /* resume thread */
            rt_ipc_list_resume(&(mutex->parent.suspend_thread));

            need_schedule = RT_TRUE;
        }
        else
        {
            /* increase value */
            mutex->value ++;

            /* clear owner */
            mutex->owner             = RT_NULL;
            mutex->original_priority = 0xff;
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* perform a schedule */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}
RTM_EXPORT(rt_mutex_release);

  3.4 rt_mutex_delete 删除互斥量

//ipc.c    几个ipc机制的delete函数都长这样;先把suspend_thread里的线程恢复到优先级表,然后RT_KERNEL_FREE(&结构体首地址);
rt_err_t rt_mutex_delete(rt_mutex_t mutex)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    RT_ASSERT(mutex != RT_NULL);

    /* wakeup all suspend threads */
    rt_ipc_list_resume_all(&(mutex->parent.suspend_thread));

    /* delete semaphore object */
    rt_object_delete(&(mutex->parent.parent));

    return RT_EOK;
}
RTM_EXPORT(rt_mutex_delete);

4 小结

  这几个ipc(inter process communication)线程间通信函数结构用法都差不多,大同小异;

标签:rt,RT,parent,thread,rtthread,互斥,mutex,owner
From: https://www.cnblogs.com/caesura-k/p/17556657.html

相关文章

  • STM32:rtthread_信号量
    1信号量  信号量是一种用于管理线程间资源关系的内核对象,线程可以获取或释放它从而达到同步或互斥的目的;  信号量可以运用在多种场合中,形成锁,同步(多个线程可访问同一资源),资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中;  1.1semaphore信号量结构体//rtd......
  • STM32:rtthread_消息队列
    1消息队列  消息队列是一种常用的线程间异步通讯方式;   消息队列能够接收来自线程或中断中不固定长度的消息,并把消息缓存在自己的内存空间中,供线程间进行异步通讯;  1.1结构体定义//rtconfig.h源码默认注释掉未开启,用到消息队列的时候需要自己开启;#defineRT_USI......
  • STM32:rtthread_f1移植
    本文开始移植rtthread的代码到正点原子的板子上;参考资料为野火的教程,需要搭配野火教程使用;使用源码是作为pack包放在arm-keil官网下载的nano3.0.3版本;nano版本精简方便解构;gittee上的master版本组件又多又杂不利于初学;本来想用3.1.5版本源码的,但是移植过程会有代码报错又莫名其......
  • GIL锁,互斥锁
    一、GIL锁1、全局解释器锁(GlobalInterpreterLock,简称GIL)GIL是一种用于保护Python解释器在多线程环境下的数据完整性的机制。GIL只存在是CPython解释器中,即官方的Python解释器实现GIL是一个互斥锁,你可以使用多线程来并发处理任务,但在同一时刻只能有一个线程......
  • 韦东山freeRTOS系列教程之【第四章】同步互斥与通信
    文章目录系列教程总目录概述4.1同步与互斥的概念4.2同步与互斥并不简单4.3各类方法的对比系列教程总目录本教程连载中,篇章会比较多,为方便同学们阅读,点击这里可以查看文章的目录列表,目录列表页面地址:javascript:void(0)概述本章是概述性的内容。可以把多任务系统当做一个团队,......
  • Linux多线程09-互斥锁
    为避免线程更新共享变量时出现问题,可以使用互斥量(mutex是mutualexclusion的缩写)来确保同时仅有一个线程可以访问某项共享资源。可以使用互斥量来保证对任意共享资源的原子访问。互斥量有两种状态:已锁定(locked)和未锁定(unlocked)。任何时候,至多只有一个线程可以锁定该互斥量。试......
  • STM32:rtthread_schedule调度
    rtthread作为多线程管理的实时操作系统,那么线程与线程之间又是如何切换管理的呢?rtthread中对于多线程切换是通过优先级表搭配优先级组进行调度的,优先级表中存储切换的上下线程节点,优先级组用来判断当前的最高优先级;为了方便理解,在引入优先级表和优先级组之前,需要先了解一下什么......
  • STM32:rtthread_"rt_timer"定时器
    1定时器  轮询系统和前后台系统中的延时为直接阻塞延时,让函数一直等着直到延时够了再继续执行;  大概rtthread觉得直接阻塞延时效率不够高,逻辑不够优美;所以它给每个thread都配置了一个rt_timer类型的thread_timer定时器;  所有定时器由定时器链表统一管理,通过对thread_ti......
  • std::thread 二:互斥量(lock() & unlock())
     mutex 互斥量的作用是保护共享数据*:有lock() 就一定要有 unlock()#include<iostream>#include<thread>#include<mutex>#include<list>usingnamespacestd;classA{public:voidinNum(){for(inti=0;i<10000;i++)......
  • std::thread 二:互斥量(lock_guard())
    *:使用lock_guard后,就不可以使用lock()和unlock()*:lock_guard和智能指针一样,会自动解锁 #include<iostream>#include<thread>#include<mutex>#include<list>usingnamespacestd;classA{public:voidinNum(){for(inti=0;......