Reputation: 13
I'm building an embedded system in qt/Linux with several finite state machines. Each FSM has its own event queue and a thread function running continuously. The FSMs may post events to each other.
Apparently the event queue should be locked and unlocked when accessing. Should I place the mutex in the FSM, EventQueue or make it global variables passing to the FSM?
Here is the pseudo code:
class EventQueue {
int queue[100];
int head;
int tail;
void postEvent(int event) {
// place the event to circular buffer
// checking of head/tail neglected
queue[tail++] = event;
}
int getNextEvent() {
// checking of head/tail neglected
return queue[head++];
}
bool isEmpty() {
return false; // or true if the queue is not empty
}
};
class FSM {
EventQueue queue;
FSM * other;
pthread_t thread;
void start() {
int t = pthread_create( &thread, NULL, FSM::run, NULL);
}
// thread function
void * run(void *) {
while (true) {
if (!queue.isEmpty()) {
int e = queue.getNextEvent();
dispatch(e); // should be perform by state class actually
}
}
}
virtual void dispatch(int event) = 0;
};
class FSM_A : FSM {
void dispatch(int event) {
other->postEvent(1234); // send event to other state machine
usleep(100);
}
};
class FSM_B : FSM {
void dispatch(int event) {
other->postEvent(4567); // send event to other state machine
usleep(200);
}
};
void main() {
FSM_A fsmA;
FSM_B fsmB;
fsmA.other = &fsmB;
fsmB.other = &fsmA;
fsmA.start():
fsmB.start():
}
Thanks!
Upvotes: 1
Views: 432
Reputation: 935
I think the easyest solution is to mutexlock your your queue.
class EventQueue {
int queue[100];
int head;
int tail;
Mutex mutex; // std::mutex or QMutex or whatever you prefer.
void postEvent(int event) {
MutexLocker( mutex ); // f.e. QMutextLocker or std::lock_guard
// place the event to circular buffer
// checking of head/tail neglected
queue[tail++] = event;
}
int getNextEvent() {
MutexLocker( mutex );
// checking of head/tail neglected
return queue[head++];
}
bool isEmpty() {
// No lock is needed if no variables are read.
return false; // or true if the queue is not empty
}
};
If a variable is read/written from more then one thread, it is important that every read or write instruction is locked while the read/write is in progress.
You don't need to lock each command queue when one of them is accessed. I would place the mutex in the EventQueue
edit: as pointed out in the comments, it's a lot safer to use a MutexLocker to lock your mutex. This way you are sure it will be released when the function scope ends.
Upvotes: 2
Reputation: 1495
Follow the Single Responsibility principle in SOLID design methodology..If the class FSM uses the eventQueue, and EventQueue internally manages it's queue of events, then, it's EventQueue's responsibility to handle it's own internal queue usage.The FSM need not be bothered about internals of EventQueue..
Upvotes: 1