General Program Structure Question

jorsborn wrote on Friday, April 19, 2013:

I have a general FreeRTOS question…

I have 4 main tasks which need to be executed in a mutually exclusive fashion. Some of the tasks will release the mutex after they have run completely and others hold it until prompted by external events (user IO interrupts). These tasks prompted by external events need to be give the mutex in a graceful manner (needs to clean up before giving). Since it can’t be ripped away, this shouldn’t be a problem. This all seems like a good fit for mutexes but how do I best signal a task to give up the mutex? A global flag? A message queue? Something else?

Any suggestions welcome… Thanks!

davedoors wrote on Friday, April 19, 2013:

Does the task holding the mutex block to wait for the external event? If so then the external event can wake the task using a semaphore, and the task holding the mutex can do its clean up and release the mutex when it unblocks.

richard_damon wrote on Saturday, April 20, 2013:

A mutex sounds like a good tool for the exclusion (that’s what it is for). I think you need a better description of how these task that hold onto the mutex until told otherwise are supposed to be working, and what sort of things are supposed to tell it to give it up. There are a number of dangers in this sort of arrangements, not the least is that the tasks that want to grab it for a defined period may have a long wait to get the mutex depending on the long holding tasks maximum response time to the request to give it up.One issue is that how ever you set up your signaling, you need to be very careful about races.

jorsborn wrote on Saturday, April 20, 2013:

Thanks for the input! I’ll try to give a bit more information about what I envision for the tasks. It seems straight forward but I want to avoid any pitfalls…

Task 1 blocks and holds the mutex until an average ADC value is greater than or equal to some value. When it receives user input notification it ignores it (but still needs to know of the user input). When the ADC value reaches the trheshold, it will relinquish the mutex.

Task 2  and 3 are similar in that they contain state machines. Of the 5 possible user input buttons, two of them advance the states inside the task and the others cause the task to release the mutex. The process of releasing the mutex is rather quick (10 ms) and so wouldn’t cause any noticeable delay from the users perspective.

Task 4 contains a bit of code that once executed runs for a good 30 seconds. This bit of code is triggered based on an external interrupt (using semaphore?). Once triggered, it should not relinquish the mutex until done. So, task 4 has an idle state where it does a few things and it has a triggered state where it can’t be interrupted.

A few of the tasks (2,3 and 4) share access to a particular piece of hardware. However, as long as they cleanup before giving up the Mutex this shouldn’t be a problem at all.

Task 1 should be able to ‘command’ the other tasks to give up the mutex EXCEPT when task 4 has been ‘triggered’ and is doing its thing.


richard_damon wrote on Sunday, April 21, 2013:

It almost sounds like these tasks are basically mutually exclusive in running, and all these tasks are sharing input from a common source. This is often a sign that the tasks are partitioned wrong. It might make more sense to have one independent user interface task monitoring your user input, and processing task that switches between several major states which are your currently defined tasks. Being a single task, the states are by definition exclusive, and the interactions for moving from one start to another may be simpler.

jorsborn wrote on Monday, April 22, 2013:

Hmmm… that’s kind of what I have right now. I have the user input (interrupt driven from different sources) setting flags. The main task has a large state machine. It interprets the user input flags which alters the states (along with time). It just seems like a messy approach with the flags and all.

richard_damon wrote on Tuesday, April 23, 2013:

Generally, taking a large state machine and breaking it up into separate tasks doesn’t make things neater, UNLESS, there is a way to simplify the state machine by doing so. This tends to happen when sequential operations can be made parallel, but in your case due to the exclusivity dependency on the hardware, sounds like this isn’t a possibility.