In the type of embedded programming I'm getting into, determinism and transparency of the running code are highly valued. What I mean by transparency is, for instance, being able to look at arbitrary sections of memory and know what variable is stored there. So, as I'm sure embedded programmers expect, new is to be avoided if at all possible, and if it can't be avoided, then limited to initialization.
I understand the need for this, but don't agree with the way my coworkers have gone about doing this, nor do I know a better alternative.
What we have are several global arrays of structures, and some global classes. There is one array of structs for mutexes, one for semaphores, and one for message queues (these are initialized in main). For each thread that runs, the class that owns it is a global variable.
The biggest problem I have with this is in unit testing. How can I insert a mock object when the class I want to test #include
s global variables that I don't?
Here's the situation in pseudo-code:
foo.h
#include "Task.h"
class Foo : Task {
public:
Foo(int n);
~Foo();
doStuff();
private:
// copy and assignment operators here
}
bar.h
#include <pthread.h>
#include "Task.h"
enum threadIndex { THREAD1 THREAD2 NUM_THREADS };
struct tThreadConfig {
char *name,
Task *taskptr,
pthread_t threadId,
...
};
void startTasks();
bar.cpp
#include "Foo.h"
Foo foo1(42);
Foo foo2(1337);
Task task(7331);
tThreadConfig threadConfig[NUM_THREADS] = {
{ "Foo 1", &foo1, 0, ... },
{ "Foo 2", &foo2, 0, ... },
{ "Task", &task, 0, ... }
};
void FSW_taskStart() {
for (int i = 0; i < NUMBER_OF_TASKS; i++) {
threadConfig[i].taskptr->createThread( );
}
}
What if I want more or less tasks? A different set of arguments in the constructor of foo1? I think I would have to have a separate bar.h and bar.cpp, which seems like a lot more work than necessary.