Page 1 of 1
A big one..
Posted: Mon Dec 08, 2008 2:09 pm
When trying to find out why my rigid bodies suddenly jump to numbers like 1e8 (which is curiously almost always the initial value for an uninitialised float..), I came across this:
When having multiple threads that write to the log via COUT(.), it can get very nasty. You then get something like "position: position: (1,1,1)" instead of "position: (1,1,1)\n position: (1,1,1)".
It can be easily explained when you consider that there is another thread in the network, also trying to write to the stream with a high level (for instance five). Now when getting to the "(1,1,1)" part, the level was already set to five instead of 0 as intended.
The main problem I see is the fact that you can feed the OutputHandler more and more data with the << operator, so there is no way to know when it is done.
By thinking not too far, I can provide two solutions to this:
1) Change the logging format to COUT(level, text). But thats obviously quite a bad idea.
2) Make a mutex and wait for std::endl to go through the stream and release the mutex.
Btw: I could somewhat prove my theory my removing all COUTs in the network library. The output then worked as expected.
Posted: Mon Dec 08, 2008 7:27 pm
Hm yes, that sounds pretty reasonable. But I think neither 1) nor 2) is a good solution, 1) because it's completely against the usual cout syntax and 2) because endl could be very well replaced by \n or no endline at all
(think of something like this:
Code: Select all
COUT(3) << "hello";
COUT(3) << "myfunction says: ";
COUT(3) << std::endl;
Code: Select all
COUT(3) << "a";
COUT(3) << "b";
COUT(3) << "c";
COUT(3) << std::endl;
which of course makes not much sense but would lock the whole program)
I think the main problem is the network thread accessing the COUT function which is itself a mistake. You shouldn't do that, not with a normal function, not with COUT and neither with std::cout, this is just against everything we know about threads.
So these are my two possible solutions:
1) no COUT at all in the network thread
2) use a threadsafe queue for (network-)thread-couts (the main-thread flushes the queue every tick)
Posted: Mon Dec 08, 2008 7:41 pm
x3n said most of the things I would have said to this. I too recommend piping the output to the main-thread, which handles the output to the shell. This would of course delay the output and makes debugging with output more difficult, but there is no better solution when garbled output is no solution.
Posted: Mon Dec 08, 2008 7:51 pm
Yeah, I didn't like neither of my solutions as well ^^ I just also wanted to be constructive
The std::endl solution was more of a joke since there were dozens of examples popping up in my head... The first solution however was serious, but I still don't like it. Ogre uses that..
I like the pipe because that's the way it should be done. I do have a little objection here: What about multithreading our application? Personally I am and always will be against it, because we completely lack the necessary experience. But I did seem to be quite alone with that opinion. So, what about it, do you still intend to multithread anything?
And anyway, if you do, I have a strong feeling that the multithreading part will be quite isolated, like the Tcl threads, so piping the output will not be a problem. Or what do you think?
Posted: Mon Dec 08, 2008 8:00 pm
I still think that multithreading is something to consider. Especially with quad cores coming up, we should use the possibility of splitting the computations. I don't think that piping the output will hurt that much and as long as we do not have actual plans about multithreading we might as well do whatever we want. And yes I know that this attitude will lead to problems when we actually consider multithreading in the future
Posted: Mon Dec 08, 2008 8:12 pm
Well, personally I really don't want to make whole Orxonox multithreaded. But as you said, small isolated parts could be multithreaded with reasonable effort. It just depends on the definition of small parts and reasonable effort
But something like the mainloop/tick is definitively not in this area.
Posted: Tue Dec 09, 2008 1:10 pm
I think it shouldn't be a big problem removing debug output from the network receiver thread.
but it might be good if we had a possiblility to pass output from slave threads to a buffer in the core without having to do this everytime we need output in a seperate thread.
do you think this would be feasible ?
Posted: Tue Dec 09, 2008 3:11 pm
I think we might be able to create output pipes for every thread. There is still the problem to decide what input "belongs" together. I mean how can you decide when which output gets written to the shell?
Imagine the network and the main thread both output something at the same time each consisting of three parts (text, variable, endl).
How shall the pipe how to group these messages together? Time chunks might be a solution, but there's still a chance of bad input formatting.
Does anybody have an idea?
Posted: Tue Dec 09, 2008 4:47 pm
Yes, when working with a queue we would have to drop the COUT(level) << text << var << endl; notation and move over to COUTQUEUE(level, output) or something similar which is ugly and sad, but otherwise we wouldn't solve anything at all with a queue. Or are there better solutions?
edit: Of course this would only be needed when cout-ing from a thread.
Posted: Sat Dec 13, 2008 7:27 pm
Never mind my question before. I was actually asking myself where to put the queued output. It could still be that the whole queue content gets stuck between text and std::endl of the main thread.
5% more thinking then revealed the catch not being an issue after all