More on C++ with an RTOS
I recently wrote about an interesting C++ programming technique, that is particularly useful in some embedded applications. The idea was all about using an embedded block, with an object local to it, where the associated constructor and destructor were put to novel use. The application, that I illustrated, was protecting a critical section using the disabling of interrupts. Today, I would like to explore the technique a little further …
The approach, that I discussed before, of turning interrupts off and then back on again, should be used sparingly and with great care, as it can have a drastic impact on the behavior and performance of a real-time system.
In a multi-threaded [multitasking] system, it is common to have a resource – commonly a hardware device – that only be sensibly used by a single task at a given time. For example, if there is a textual display, a task might need have exclusive use to output some information. If two tasks tried to access the device at the same time, their text would get mixed up. The usual RTOS object to use to control access/ownership of a device is a binary semaphore. We might create a class like this:
class Grab_Console { private: static Semaphore console_lock; public: Grab_Console() { console_lock.obtain(); }; ~Grab_Console() { console_lock.release(); }; };
A few things to note:
- A class Semaphore is assumed to be available. This simply uses the RTOS’s API to create and manage a binary semaphore.
- This class has member functions [methods] called obtain() and release() that provide the obvious functionality.
- The Semaphore object console_lock is declared static so that a single instance is shared between all objects instantiated from Grab_Console.
A task wishing to speak to the world might now be coded thus:
... { Grab_Console now; printf("Hello World!\n"); } ...
Clearly there are numerous potential applications of this approach.
After my last posting, it was pointed out to me that this approach is particularly compatible with C++ exception handling [thanks Sam]. Although it is rare to use exception handling in embedded applications, because of the extra overheads, if it is employed, you can be sure that, if the “protected” code throws an exception, the destructor will still be executed. We might term it as “EHS-safe”.
Comments
Leave a Reply
You must be logged in to post a comment.
Isn’t this the typical RAII approach (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)?
Also the example code can actually be refined into the form of std::lock_guard() and std::scoped_lock().
@Alfred: Absolutely. I was not claiming to have invented this approach, but, you are right, I should have labelled it. I do have some reservations about using those library functions in a real time system.
I think this approach works only under the assumption that the instantiation is preceded the call of printf. -> You have to remember this, everytime where you want to use printf.
How do you want to prevent the declaring of a static instance of the Grab_Console class? If you do this the contructor will never be called and the semaphore will never be released.
I meant in my last sentence „the destructor will never be callled„.