I am trying to get uox3 working better with linux so I started making a few thread classes so modifcations can be made easily. I currently have cThread, cMutex and cMessageQueue. I started to try and integrate and the cConsole class being the only major thread (I think) in the code that I can see. I want to move out the console polling (which is in uox3.cpp) into the cConsole class and derive it from my Thread class so it can be spawned from the main loop.
The Console I/O needs to be thread-safe. Take for example multiple threads using
cConsole.Print("Something");
If the thread was preempted in the middle of a print and another thread wanted to print to you could possible get something like
"SomeSothingmething"
Is this an issue for UOX3? I don't think it is at the moment. There are 3 threads I think and only 1 of them sends to the console so that is ok. If other threads wanted to print it could possibly be a problem.
The implementation I was thinking of was each working thread would post to the thread. So say we have
cConsole::Print("blah"); that another thread wants to print. The string "blah" would be added to the cConsole internal message queue (which is thread safe). The cConsole thread would then poll both the input and check the message queue size in it's path of execution. This is the easiest way I was thinking of without interfering with the class' interface.
However - I ran into a problem. I just realised tha cConsole is a really a state machine and it isn't really thread-safe.
So what makes it not thread-safe in my implementation and what is my difficulty? Well, other threads can change the state of the console (position and colour) without posting to the message queue. So, my question is how would I implement it so the console still does all the nifty things it does (like colours and the loading cursor) but remain thread-safe?
Threading and cConsole
I was looking at the cConsole class again and I was wondering how it could be changed so it would be both thread-safe and more adaptable. The cConsole class handles both File Logging and Console stuff. It probably would be best to decouple these two seperate things. I came to the conclusion that the observer design pattern could be used.
Basically what will happen is this:
We have a class - lets call it cLogger which performs all the relevent logging functions LogWarning/LogError/LogInfo etc.
http://sern.ucalgary.ca/courses/SENG/60 ... erLib.html
According to the Observer design pattern the cLogger class will now be the "subject". Now we create a cConsole class and call this the "observer". The "observer" registers it's interest in the "subject" and hence registers with the class. Basically when cLogger class gets a LogWarning or LogError it dispatches the event to all registered "subjects" which in this case would be the cConsole class. The cConsole class can then do what it likes with event - (which most obviously would be to write it to the console.)
Why do I like this model?
Firstly, we always want to log to a file regardless if we have a console or not. Also we might not want a console class all the time. For instance in Linux, a user might not want a console class - one might want the server to run fork()'ed in the background - in this case the console class can easily be decoupled from the Logger subject by just not registered with it (or just deregister once it has forked). Also in Linux one might want to send errors etc. to the system logger as well as have a console. This is easily to do as the pattern can have many observers registered to the subject. Another possible addition is a GUI. One could create a GUI Interface easily without modifying anything else in the code. Just a simple registering with the Logger class and the GUI can be notified of all log features.
Anyway what do you think of this additon. I could possible implement this as I would find it interesting to do.
Basically what will happen is this:
We have a class - lets call it cLogger which performs all the relevent logging functions LogWarning/LogError/LogInfo etc.
http://sern.ucalgary.ca/courses/SENG/60 ... erLib.html
According to the Observer design pattern the cLogger class will now be the "subject". Now we create a cConsole class and call this the "observer". The "observer" registers it's interest in the "subject" and hence registers with the class. Basically when cLogger class gets a LogWarning or LogError it dispatches the event to all registered "subjects" which in this case would be the cConsole class. The cConsole class can then do what it likes with event - (which most obviously would be to write it to the console.)
Why do I like this model?
Firstly, we always want to log to a file regardless if we have a console or not. Also we might not want a console class all the time. For instance in Linux, a user might not want a console class - one might want the server to run fork()'ed in the background - in this case the console class can easily be decoupled from the Logger subject by just not registered with it (or just deregister once it has forked). Also in Linux one might want to send errors etc. to the system logger as well as have a console. This is easily to do as the pattern can have many observers registered to the subject. Another possible addition is a GUI. One could create a GUI Interface easily without modifying anything else in the code. Just a simple registering with the Logger class and the GUI can be notified of all log features.
Anyway what do you think of this additon. I could possible implement this as I would find it interesting to do.
I love the idea!
I am not sure you can enforce thread safety on the actual console (IE, preventing someone from just resetting the position/color without going through your class), or at least I do not know how you would do that.
As for the print conflict, just throw in a mutex lock at the beginning of the function and clear it at the end? Or is it not that simple? I really have no experience in a multi-threaded environment, but I hear speak of “race conditions” all the time, which might be a bigger issue than simply getting two messages glued together. I do not really know what happens during a “race condition”, though, just that it happens when two threads try to access the same variable at the same time.
I really like the decoupling idea, at any rate, since it would make making a new GUI a breeze.
I am not sure you can enforce thread safety on the actual console (IE, preventing someone from just resetting the position/color without going through your class), or at least I do not know how you would do that.
As for the print conflict, just throw in a mutex lock at the beginning of the function and clear it at the end? Or is it not that simple? I really have no experience in a multi-threaded environment, but I hear speak of “race conditions” all the time, which might be a bigger issue than simply getting two messages glued together. I do not really know what happens during a “race condition”, though, just that it happens when two threads try to access the same variable at the same time.
I really like the decoupling idea, at any rate, since it would make making a new GUI a breeze.