richard_damon wrote on Tuesday, March 26, 2013:
A good RTOS should actually help here more than hurt., at least as long as your requirements are indicative of using one (Needing rapid responses to some inputs). Anytime you have multiple threads of execution accessing common data, there are issues of needing interlocks of some form, this is fundamental. There are 3 basic ways to meet “Real Time” timing requirements:
1) Put such a fast processor in that it can meet the requirements with non-pre-emptive code, this will often become expensive and power hungry. If it doesn’t, than this may well be the best choice.
2) Do the critical timing in an interrupt routine, and have a single threaded main loop handling the rest. This doesn’t need a OS, and limits the limits how much code need to deal with pre-emptive issues, but that code is more difficult as you have less tools to deal with them, and the tools tend to be broader in effect. Typically critical sections of code will need to disable interrupt, causing added latency, or critical operations done inside an interrupt routine, possible delaying other critical operations. This may be the solution if you have just a few real time requirements.
3) Use a Real TIme operating system to manage your requirements. Interrupt routines exist to field hardware request, and perhaps handle some of the most critical operations, while tasks handle the rest.
A key aspect that needs to be dealt with is working with shared data. Generally a piece of code should “own” the data that it is using, and not be sharing it at that moment. The one major exception is data so simple that its changes are “atomic” (and you need to be very careful then that all accesses ARE done atomically). A RTOS will provide the tools to allow the various parts of the program to share and take ownership of the pieces of data it needs to use.
Where you are seeing “subtle problems cause by RTOSes”, it normally isn’t a problem caused by the RTOS, but by the definition of the requirements of the system, having defined data shared between two unsynchronized sections. Once the concept of proper ownership of data is put into place, then the only problem left is finding the right tool to implement it, which is what the RTOS will (hopefully) provide.
In the case presented, if there is a single buffer, which can be owned, sequentially, by one of several tasks at a time, then semaphores provide a good solution. From the problem statement I would use TWO semaphores, one to grant access by a producer, and one for access by the consumer. A producer grabs the producer semaphore, and when it has it, fills it with data. When done is sets the consumer semaphore. Thus no producer can access the buffer yet, as it is busy. When the consumer gets its semaphore, it can empty the buffer and then raise the producer semaphore, letting the next producer work. There is no need for a queue (except in how semaphores are built on queues), as all you are passing between tasks is the fact of availability of THE buffer
A second method, if you want to allow producers to not need to wait to generate data, would be to have a set of buffers. Each producer when it wants to generate data, gets a buffer from a source (perhaps a queue holding the list of buffers), fills the data, and then posts the address of the buffer to a queue for the consumer. The consumer then gets that address, consumes it, and returns it to the free buffer store.
In both of these methods a/the buffer is in one of several states: empty/ready for a producer, being used by a producer, full waiting to be consumed, being consumed. In each state its ownership is clear, and so is who can access/modify the data.