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