互斥量不能在中断例程中使用的原因
背景
今天在看资料,发现在互斥锁这一块儿,有用法要求,说是 互斥锁不能在中断服务程序中使用。
但是为什么不能用呢?却没见文章中有写,于是顺着这条线向找。
解释
从RT-thread论坛上看到的解释如下:
如果在中断例程中能使用互斥量,万一其他更高优先级的中断来了,需要互斥量,但获取不了,导致中断处理阻塞,而中断是不能阻塞的。
https://club.rt-thread.org/ask/question/5dc901cf99025727.html
疑点
获取mutex时,有一个time_out参数,可以设置为0,那么即不产生BLOCK,是不是就可以在中断中使用了呢?
于是我翻了一个源代码找到了这一段
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;
/* parameter check */
RT_ASSERT(mutex != RT_NULL);
RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex);
/* get current thread */
thread = rt_thread_self();
....
}
好家伙,源代码中的注释部分,直接说明了 this function must not be used in interrupt even if time = 0
,再向下看,找到了thread = rt_thread_self();
这说明这个锁仅为线程之间进行设计,若使用了,将会产生不可预知的错误。
我翻了一下ucOS-III源代码,发现ucOS-III源码中直接拦截了。
void OSMutexPend (OS_MUTEX *p_mutex,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)
{
OS_TCB *p_tcb;
CPU_SR_ALLOC();
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
OS_TRACE_MUTEX_PEND_FAILED(p_mutex);
OS_TRACE_MUTEX_PEND_EXIT(OS_ERR_PEND_ISR);
*p_err = OS_ERR_PEND_ISR;
return;
}
#endif
....
}
void OSMutexPost (OS_MUTEX *p_mutex,
OS_OPT opt,
OS_ERR *p_err)
{
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
CPU_TS ts;
OS_PRIO prio_new;
CPU_SR_ALLOC();
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { /* Not allowed to call from an ISR */
OS_TRACE_MUTEX_POST_FAILED(p_mutex);
OS_TRACE_MUTEX_POST_EXIT(OS_ERR_POST_ISR);
*p_err = OS_ERR_POST_ISR;
return;
}
#endif
....
}
结论
互斥锁量是专门为任务与任务之间共享资源而设计,不适用中断的场合。