rtthread:互斥量
1 互斥量
互斥量即互相排斥的信号量,是一种特殊的二值信号量;只能由持有线程释放,而信号量则可以由任何线程释放;
拥有互斥量的线程拥有互斥量的所有权,互斥量支持递归访问且能防止多线程优先级翻转;
1.1 线程优先级翻转问题
互斥量通过继承线程优先级,将持有互斥量的线程优先级提高到和挂载到suspend_thread的线程优先级一样高,这样就不会有低优先级的线程反而先被调度执行了;
2 mutex 结构体
//rtconfig.h 默认注释了define,用到的话需要自己开启; #define RT_USING_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)线程间通信函数结构用法都差不多,大同小异;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?