I have one init
task and several worker tasks. At some point the workers must wait for init
to complete some setup. I'm trying to do this with a binary semaphore.
When the scheduler starts, all tasks are ready to run. So to guarantee that the workers wait, the semaphore must be "taken by the init
task" before the scheduler starts. (Otherwise a worker could get the semaphore before init
was even scheduled.)
How do I do that? Or how else should I solve that problem?
A binary semaphore would work if you only had one worker task. You would create the semaphore as "unavailable" / "taken", and the init task would xSemaphoreGive the semaphore when initialization is done, notifying the single worker task that initialization was complete. However, when you have several tasks, then only one of them will be able to take/acquire the semaphore.
A counting semaphore would work. The semaphore should have a capacity equal to the number of worker tasks, and it should start as empty. As system designer, you know that the init-task is designed to own the underlying resource at startup, so init-task won't have to acquire the semaphore on the first initialization. After initialization, you should call xSemaphoreGive once for each worker. When/if you want to reinitialize, call xSemaphoreTake once for each worker task. For this to work, the workers must periodically "release" the semaphore briefly and then reacquire it.
An Event Group could also be used if you'll only initialize once. Your init-task can use xEventGroupSetBits to indicate that initialization is complete. Your worker tasks can use xEventGroupWaitBits to wait until the init-task is done.
When you have multiple tasks waiting for a signal or event then a binary semaphore is not the right mechanism. With a binary semaphore, only one task can take the semaphore at a time and only one task will be made ready to run when the binary semaphore is given. I suppose each waiting task could take and then immediately give the semaphore to the next waiting task but that seems strange.
Can you simply make the Init task the highest priority task until it has completed the necessary initialization. The other tasks won't run until initialization is complete by virtue of being lower priority. When initialization is complete you could delete the Init task or maybe lower it's priority.
If priority is not an option then you should probably use an event bit (event flag). For your use case an event bit is a better mechanism than a binary semaphore because multiple waiting tasks can be made ready to run when the Init task signals the event.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With