Intertask Synchronization
Intertask synchronization refers to that one task can only keep on executing after it has got the synchronization signal sent by another task or the ISR. There are semaphores, mutexes and flags to implement intertask synchronization in CooCox CoOS.
Semaphores provide an effective mechanism for the system to handle the critical section and implement intertask synchronization.
The action of semaphore can be described as the classical PV operation:
P Operation: while( s==0); s--;
V Operation: s++;
You can create a semaphore by calling CoCreateSem ( ) in CooCox CoOS. After the semaphore has been created successfully, you can obtain it by calling CoPendSem ( ) or CoAcceptSem ( ). If there is no free semaphore, CoPendSem ( ) will wait for a semaphore to be released while CoAcceptSem ( ) will return the error immediately. You can also call CoPostSem ( ) in the task or isr_PostSem ( ) in the ISR to release a semaphore for the purpose of achieving synchronization.
Code 1 The creation of the semaphore
ID0 = CoCreateSem(0,1,EVENT_SORT_TYPE_FIFO); // initCnt=0,maxCnt=1,FIFO
ID1 = CoCreateSem(2,5,EVENT_SORT_TYPE_PRIO); // initCnt=2,maxCnt=5,PRIO
Code 2 The use of the semaphore
void myTaskA(void* pdata)
{
..........
semID = CoCreateSem(0,1,EVENT_SORT_TYPE_FIFO);
CoPendSem(semID,0);
..........
}
void myTaskB(void* pdata)
{
......
CoPostSem(semID);
......
}
void myISR(void)
{
CoEnterISR ( );
......
isr_PostSem(semID);
CoExitISR ( );
}
Mutexes have solved the "mutually exclusion" problem in CooCox CoOS. It forbids multiple tasks to enter the critical code section at the same time. Therefore, only one task can enter it at any time.
In CooCox CoOS, the mutex section has also considered the issue of priority inversion. CooCox CoOS has solved this issue by the method of priority inheritance.
Priority inversion refers to that the high-priority task is waiting for the low-priority task to release resources, at the same time the low-priority task is waiting for the middle priority task’s.
There are two classical methods to prevent the inversion at present:
1) The priority inheritance strategy: The task which is possessing the critical section inherits the highest priority of all the tasks that request for this critical section. When the task exits from the critical section, it will restore to its original priority.
2) The ceiling priority strategy: Upgrade the priority of the task which requests a certain resource to the highest priority of all the tasks that be likely to access this resource (and the highest priority is called the ceiling priority of this resource).
The priority inheritance strategy has a less impact to the flow of the task execution since it only upgrades the priority of the low-priority task when a high-priority task is requesting for the critical resource that being occupied by the low-priority task. However, the ceiling priority strategy upgrades one task’s priority to the highest when the task is occupying the critical resource.
CooCox CoOS prevents the priority inversion by the method of priority inheritance.
The following figure describes the task scheduling of three tasks when there are mutex sections in CooCox CoOS. TaskA has the highest priority while TaskC has the lowest. The blue boxes refer to the mutex sections.

You can create a mutex section by calling CoCreateMutex ( ). Calling CoEnterMutexSection ( ) and CoLeaveMutexSection ( ) to enter or leave the mutex section so that we can protect the codes in critical section.
Code 3 The use of the mutex section
void myTaskA(void* pdata)
{
mutexID = CoCreateMutex ( );
CoEnterMutexSection(mutexID ); // enter the mutex section
........... // critical codes
CoLeaveMutexSection(mutexID ); // leave the mutex section
}
void myTaskB(void* pdata)
{
CoEnterMutexSection(mutexID ); // enter the mutex section
........... // critical codes
CoLeaveMutexSection(mutexID ); // leave the mutex section
}
When a task wants to synchronize with a number of events, flags are needed. If the task synchronizes with a single event, it can be called independent synchronization (logical OR relationship). If it synchronizes with a number of events, then called associated synchronization (logical AND relationship).
CooCox CoOS supports 32 flags to the maximum at the same time. It supports that multiple tasks waiting for a single event or multiple events. When the flags that the waiting tasks waiting for are in the not-ready state, these tasks can not be scheduled. However, once the flags turn to the ready state, they will be resumed soon.
According to the types of the flags, the side effects are different when the tasks have waited for the flags successfully. There are two kinds of flags in CooCox CoOS: the ones reset manually and the ones reset automatically. When a task has waited for a flag which reset automatically, the system will convert the flag to not-ready state. On the contrary, if the flag is reset manually, there won’t be any side effect. Therefore, when a flag which reset manually converts to the ready state, all the tasks which waiting for this event will convert to the ready state as far as you call CoClearFlag ( ) to reset the flag to the not-ready state. When a flag which reset automatically converts to the ready state, only one task which waiting for this event will convert to the ready state. Since the waiting list of the event flags is ordered by the principle of FIFO, towards the event which reset automatically only the first task of the waiting list converts to the ready state and others that waiting for this flag are still in the waiting state.
Suppose there are three tasks (A, B, C) waiting for the same flag I which reset manually. When I is ready, all the tasks will be converted (A, B, C) to the ready state and then inserted into the ready list. Suppose I is a flag which reset automatically and the tasks (A, B, C) are listed in sequence in the waiting list. When I is ready, it will inform task A. Then I will be converted to the not-ready state. Therefore B and C will keep waiting for the next ready state of flag I in the waiting list.
You can create a flag by calling CoCreateFlag ( ) in CooCox CoOS. After being created, you can call CoWaitForSingleFlag ( ) and CoWaitForMultipleFlags ( ) to wait for a single flag or multiple flags.
Code 4 Wait for a single flag
void myTaskA(void* pdata)
{
..........
flagID = CoCreateFlag(0,0); // Reset manually, the original state is not-ready
CoWaitForSingleFlag(flagID,0);
..........
}
void myTaskB(void* pdata)
{
......
CoSetFlag(flagID);
......
}
Code5 Wait for multiple flags
void myTaskA(void* pdata)
{
U32 flag;
StatusType err;
..........
flagID1 = CoCreateFlag(0,0); // Reset manually, the original state is not-ready
flagID2 = CoCreateFlag(0,0); // Reset manually, the original state is not-ready
flagID3 = CoCreateFlag(0,0); // Reset manually, the original state is not-ready
flag = flagID1 | flagID2 | flagID3;
CoWaitForMultipleFlags(flag,OPT_WAIT_ANY,0,&err);
..........
}
void myTaskB(void* pdata)
{
......
CoSetFlag(flagID1);
......
}
void myISR(void)
{
CoEnterISR();
......
isr_SetFlag(flagID2);
CoExitISR();
}
|