共享资源的方法:关中断、关调度器、Sem、Mutex。
关中断:任务与中断共享资源的唯一方法(CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); *****; CPU_CRITICAL_EXIT();)。
关调度:当调度被关闭的时候,中断是开启的,当中断发生时,ISR会立即执行,执行完不管有没有高优先级的任务,都会回到被中断的任务。(OSSchedLock(); ***; OSSchedUnlock();)
Sem:最初被用在控制共享资源(创建时初始值>0),现在也被用在同步上(创建时初始值=0)。
binary semaphores:只能为0(Sem不可得,需要等待)或1(Sem可得,继续执行)。
counting semaphores:0到OS_SEM_CTR对应的最大值(当资源可以被多个任务使用时,如缓冲池)。
Mutex:一种特殊类型的binary semaphores,可以克服优先级翻转。
Sem在任务之间共享IO设备的时候非常有用,最好将处理和获取释放Sem封装起来。
优先级翻转:
L得到Sem,当H想要Sem时得不到,H被插入到等待List中,L被M终止,M执行完后,L继续执行释放Sem,H的到Sem运行。
Mutex可以解决这个问题(当高优先级任务H需要时,会将此时占用Mutex的低优先级的任务L优先级提高到和H相同)。
避免死锁的方法:
1. 先获取所有的资源,然后在处理。
2. 用同一个顺序获取资源。
3. Pend操作使用timeout。
多个任务等待一个Sem,使多个任务同时运行。(广播Broadcast是同步多个任务同时运行的通用技术)
如果不使用Flag,但可能出现一种情况,在广播时有任务没有等待这个Sem,将Sem和Flag混合使用,可以解决此问题。
typedef struct os_sem OS_SEM;
struct os_sem { /* Semaphore */
/* ------------------ GENERIC MEMBERS ------------------ */
OS_OBJ_TYPE Type; /* Should be set to OS_OBJ_TYPE_SEM */
CPU_CHAR *NamePtr; /* Pointer to Semaphore Name (NUL terminated ASCII) */
OS_PEND_LIST PendList; /* List of tasks waiting on semaphore */
#if OS_CFG_DBG_EN > 0u
OS_SEM *DbgPrevPtr;
OS_SEM *DbgNextPtr;
CPU_CHAR *DbgNamePtr;
#endif
/* ------------------ SPECIFIC MEMBERS ------------------ */
OS_SEM_CTR Ctr;
CPU_TS TS;
};
void OSSemCreate (OS_SEM *p_sem,
CPU_CHAR *p_name,
OS_SEM_CTR cnt,
OS_ERR *p_err):
创建Sem。如果是资源共享cnt为资源的个数,如果是标志某个事件的发生则为0。
OS_OBJ_QTY OSSemDel (OS_SEM *p_sem,
OS_OPT opt,
OS_ERR *p_err):
删除Sem。
OS_OPT_DEL_NO_PEND:当没有任务等待时删除,调用OS_SemClr(),如果有任务则设置错误代码。
OS_OPT_DEL_ALWAYS:即使有任务等待也删除,对等待列表中的将所有的任务调用OS_PendObjDel(),调用OS_SemClr(),启动调度。
清空p_sem中的内容,OS内部函数,被OSQDel()调用。
调用OS_PendListInit()清空p_sem的等待列表。
OS_SEM_CTR OSSemPend (OS_SEM *p_sem,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err):
等待一个Sem。
查看p_sem->Ctr是否已经被标志,是OSTCBCurPtr->SemCtr--,任务继续执行,否调用OS_Pend(),启动调度器切换到别的任务执行,任务被再次唤醒时在此继续往下运行---->
---->判断OSTCBCurPtr->PendStatus:
如果OS_STATUS_PEND_OK,*p_err = OS_ERR_NONE,返回继续执行。
如果OS_STATUS_PEND_ABORT、OS_STATUS_PEND_TIMEOUT、OS_STATUS_PEND_DEL,设置错误代码。
OS_OBJ_QTY OSSemPendAbort (OS_SEM *p_sem,
OS_OPT opt,
OS_ERR *p_err):
终止任务对p_sem的等待。
根据opt对p_sem中等待列表中的任务调用OS_PendAbort(),根据opt是否启动调度。
OS_SEM_CTR OSSemPost (OS_SEM *p_sem,
OS_OPT opt,
OS_ERR *p_err):
Post p_sem。
如果OS_CFG_ISR_POST_DEFERRED_EN>0&&OSIntNestingCtr>0,调用OS_IntQPost()(Post到ISR Queue~OS_OBJ_TYPE_SEM),否则调用OS_SemPost()。
OS_SEM_CTR OS_SemPost (OS_SEM *p_sem,
OS_OPT opt,
CPU_TS ts,
OS_ERR *p_err):
Post一个Sem,OSSemPost ()调用。
如果p_sem的等待列表中没有任务,p_sem->Ctr++。有任务则根据opt对等待链表中的任务调用OS_Post(),根据opt启动调度器
void OSSemSet (OS_SEM *p_sem,
OS_SEM_CTR cnt,
OS_ERR *p_err):
设置p_sem->Ctr为cnt。
如果p_sem->Ctr>0,则直接设为cnt,否则判断是否有任务等待,如果没有设为cnt,有则不允许。
void OS_SemInit (OS_ERR *p_err):
初始化Sem管理,设置OSSemQty= 0,OS内部函数,OSInit()调用。

28

被折叠的 条评论
为什么被折叠?



