richard_damon wrote on Wednesday, July 28, 2010:
Stefano,
First, let me repeat, that this is mostly stylistic and for many meanings of works, your method works.
As to my first comment, if you look closely at the abstraction of the classes, you classes fundamentally deal with “handles”, in that you need to explicitly put the handle into the class, you also have an explicit state of “not connected” for an object that hasn’t had a handle imbued into it. In my model, the class represents the FreeRTOS structure, and the fact that it deals with those structures via a handle is invisible. This also means that I have a clearer ownership relationship to the FreeRTOS structure, my class “owns” the structure and is responsible for it. In your case, a simple error could imbue the same handle into multiple wrappers leading to life time control issues.
Again, your second point makes it clear that in your mind you are treating the classes as wrappers for the handles, not the concepts of tasks/queue/semaphores. In my opinion, taking an existing program, and within that program take an existing task/queue/semaphore etc and suddenly add an additional variation of API is normally not productive and is error prone. If an existing task has enough “C” style references to it that you do not want to convert them, adding additional references as “C++” style would be an obfuscation, breaking the link between them mentally. From my experience, half conversions are a nightmare, either change too a C++ style or stay in C style, the mixed model loses much of the advantages of each of the style and adds few of its own. As an example, you are stuck with the C style allocation model, and can not implement RAII as it is incompatible with the C side of the mixture.
As to the duplication of code in your abstract base, the give and take routines are very small since they are mere wrappers to the FreeRTOS calls. What the abstract base allows is to write a routine that takes an ASemaphore by pointer/reference that is polymorphic, but because these are two very different type of object in usage, I don’t think it is possible to write a routine that can really take both types of synchronization primitives unless your intent is to allow the (ab)use of a semaphore as a mutex without priority inheritance. In the code that I have been working on, I keep semaphores and mutexes as separate concepts, and this doesn’t seem to have caused problems. If your base had been something like SyncronizationBase, I might think of this differently, but the name ASemaphore implies that the hierarchy implements a semaphore usage which really isn’t true. I mutex is really more than a specialization of a semaphore.
For my third comment, i don’t REQUIRE the user to derive and specialize, but allow it. One usage is to create a Task object, and pass it a pointer to a free function, and that creates a task very much as a standard FreeRTOS task, or one can derive a class from TaskClass, and this will automatically (from the provided info) create a task based on a void classname::task() member function (note that the member function doesn’t take an explicit parameter as that is used to specify the object it is called on, and that object can contain any other needed information to pass to the function).
As far as memory overhead, I believe it is negligible, my basic Task Class is the size of a task handle, which would be needed to be stored somewhere anyway (and I don’t need it stored elsewhere first). My Queue class stores a handle and a pointer to simplify the usage of the FromISR versions with the need to store the flag for the need to do a task switch. My Semaphore similarly is just a handle and pointer. My Mutex, since I did implement a common base for recursive and non-recursive mutexes to implement a RAII lock class, has a handle and a vtable pointer. All my member functions are inline and not much more than a call to the corresponding FreeRTOS function. There is no need at all for the STL, and I do not use Run Time Type Detection, and in fact, except for the mutex classes which have virtual give and take function, don’t even bring any of these into play.
I am currently working on getting the code ready for publishing, by adding proper documentation, and hopefully I will add it to the article I wrote on using FreeRTOS in C++ shortly.
The one thing it might not provide is a easy support for a mixed C/C++ model the way you are doing so. You will need to create the objects C++ style (and the C++ style will “own” the object and be in charge of deleting it if needed) and you can then extract the handle to give to the C style access to the object.
As to using MFC as a design guideline, my personal opinion is it wasn’t all that well done, and Microsoft has mostly dropped it as a design method too. It also wraps a much bigger interface than FreeRTOS.