below is a simple inter-task synchronization barrier implementation. Of course, because this is not a part of kernel, there are many assumptions of using it. The master must at first create barrier(you cannot re-enter if was not created first). After that, tasks can wait on this barrier with a timeout. If timeout expired, all waiting tasks are waken with error. The return value of function barrierState determines if there are still tasks which did not reach the barrier. Martin
typedef struct
{
unsigned portSHORT counter;
unsigned portSHORT max;
xQueueHandle xQueue;
} barrier;
#define BARRIER_SUCCESS pdTRUE
#define BARRIER_FAILED pdFAIL
unsigned portBASE_TYPE barrierTake(barrier * b, portTickType xTicksToWait)
{
unsigned portBASE_TYPE mess = BARRIER_SUCCESS;
// Enter to shared memory region
portENTER_CRITICAL();
// Increment common counter
b->counter++;
// Exit critical section
portEXIT_CRITICAL();
// Barrier reached?
if(b->counter < b->max)
{
// Not all tasks finished yet.
// Wait on the other tasks with timeout. Due to "peek" message will remain
// in message queue.
if(pdTRUE != xQueuePeek( b->xQueue, &( mess ), xTicksToWait))
{
// Timeout. Inform other tasks about missed timeout.
mess = BARRIER_FAILED;
xQueueSend( b->xQueue, ( void * ) &mess, ( portTickType ) 0 );
}
}
else
{
// If there is stored a message do not send.
if(uxQueueMessagesWaiting( b->xQueue) > 0)
{
// Receive message(peek).
xQueuePeek( b->xQueue, &( mess ), ( portTickType )0);
}
else
{
// All tasks finished.
// Inform other tasks.
xQueueSend( b->xQueue, ( void * ) &mess, ( portTickType ) 0 );
}
}
// Return status.
return mess;
}
void barrierCreate(barrier * b, unsigned portSHORT max)
{
// Used only as a dummy place(/dev/null) for flushing queue.
unsigned portBASE_TYPE mess;
// Set number of tasks to synchronize.
b->max = max;
// Reset counter.
b->counter = 0;
// Create or empty a message queue.
if(NULL == b->xQueue)
{
// Queue was not created, create....
b->xQueue= xQueueCreate( 1, sizeof( unsigned long ) );
}
else
{
// Queue was created, flush....
while(pdTRUE == xQueueReceive( b->xQueue, &( mess ), ( portTickType )0))
{
// NOP();
}
}
}
portBASE_TYPE barrierState(barrier * b)
{
// How many task was not entered into barrier?
// -1 means more than max defined tasks.
return (b->max - b->counter);
}
barrier bar;
void start(void * par)
{
barrierCreate(&bar, 4);
printf("start:%dn",barrierTake(&bar,100));
vTaskDelay(100);
printf("start: state %in",barrierState(&bar));
vTaskSuspend(NULL);
}
void A(void * par)
{
printf("A:%dn",barrierTake(&bar,portMAX_DELAY));
printf("A1:%dn",barrierTake(&bar,portMAX_DELAY));
vTaskSuspend(NULL);
}
void B(void * par)
{
vTaskDelay(1);
printf("B:%dn",barrierTake(&bar,portMAX_DELAY));
vTaskSuspend(NULL);
}
void C(void * par)
{
printf("C:%dn",barrierTake(&bar,portMAX_DELAY));
vTaskSuspend(NULL);
}
int main()
{
xTaskCreate( start, "start", 100,NULL,4, NULL );
xTaskCreate( A, "A", 100,NULL, 3, NULL );
xTaskCreate( B, "B,", 100,NULL, 2, NULL );
xTaskCreate( C, "C", 100,NULL, 1, NULL );
/* Start the scheduler, this function should not return as it causes the execution
context to change from main() to one of the created tasks. */
vTaskStartScheduler();
/* Should never get here! */
return 0;
}