While implementing some thread save FB's for accessing a cascadable Raspberry Pi IO board I came across a general question about the order of creating tasks in contrast to the order of the creation of semaphores being used by these tasks.
In the embedded world or any other kind of "have a proper run-level boot-up" system I'd first create my synchronisation objects and thereafter the threads using them. At least I would take care for first starting the threads after all synchronisation objects (mutexes, semaphores, queues) are in place and are initialized.
However, tasks being created in the IDE of CODESYS do seem to be initialized and started by the runtime with no further controlling mechanism from within the (STL) user code being executed. Thus tasks are being created prior to the synchronisation objects which they are supposed to be using. Well, one could think of using some singleton in order to create all these sync objects during the first task cycle. However, not knowing about the thread order to be executed this code would have to rather be located in a globally used object (thus not ideal when trying to encapsulating synchronisation objects as static members of a class e.g. when writing some library code). But even then we encounter a problem. Let's take a look at the code below which creates a semaphore.
IF hMutex = RTS_INVALID_HANDLE THEN
hMutex := SysSem.SysSemCreate(ADR(mutexCreateResult));
// From now on use the mutex.
This code (being executed by several threads) is not 100% thread safe. Why's that? Simply because it relies on the fact the assignment to hMutex itself would be an atomic operation. But strictly speaking this is not ensured! The handle is implemented as a 4Byte value and there is no saying that the assignment is an atomic operation. It is a matter of the compiler how to deal with it.
One could now think of enclosing the assignment within another variable of type BOOL which suggests that it can be read and written to in an atomic operation - however, this can also fail as for code reordering of the compiler if there is no way of establishing something like a memory barrier.
So the ultimate question is - how can sync objects be created prior to tasks running? Or otherwise - is there a way in the runtime to inject code during the initialization of the application?