Thread overview
win::cout, win::clog, win::cerr output for Windows
Feb 18, 2003
Richard Grant
Feb 19, 2003
Walter
Feb 19, 2003
Richard Grant
Feb 19, 2003
Jan Knepper
Feb 19, 2003
Richard Grant
Feb 19, 2003
Jan Knepper
Feb 20, 2003
Richard Grant
February 18, 2003
Hi,

I just finished a project in MFC, and everything was going smoothly right up until the end. Defining the interface with resource editor was easy, creating controls in code was trivial.. Using the Data Exchange to get access to the control data seemed a little contrived, but worked well. All in all a fairly complete application with minimal effort.

Then I ran into an intermittent access violation. Ok, so I reached into my usual bag of tricks, and realized - how was I going to output program state using a windowing interface that was itself exhibiting problems. Rats. No std::cout to play with, and typed variables everywhere. Also the program was 3MB and my code couldn't have been more then 2 or 3 hundred lines.

Anyway, after I finished stuffing MessageBox with stringstream managed strings, and dropping them into various places, I eventually found the problem. It looked like something to do with Thread Local Storage being instantiated improperly. I've worked with TLS before, so I looked around in the MFC code but gave up after about 10 seconds.

I just restructured the code in places that seemed suspect: 1) using a static member function as control routine of AfxBeginThread, 2) having my own defined default c'tor and d'tor for theapp, 3) Passing the class of the static member function as the argument of the thread start, and casting from void to the class. And 4) starting the thread in oninitdialog instead of initializeapp. Everything seemed to work fine after that. Not that I thought what I was doing was illegal, just that they seemed like places the framework authors might get confused.

The point is, I think I would have spent considerably more time trying to identify the problem if there were an iostream based variable like "win::cout" ("win" being a namespace qualifier). I did some minimum looking around, and was amazed that there was very little material on this issue. What with the continued success of Windowing environments, I would have thought that such a subject would have already been exhausted.

I did find a macro at the Code Project "cout", but I hate macros - mostly due to the if (bool) macro; problem where the macro expands into more than one line. But that's really a personal distaste. Still, you get some typing and such, but I don't really like the format. I prefer to decide when a newline will appear, and what title to give my output. And why should I define the console?

Since I don't program that often for GUI deployments, I am not certain what features win::cout would have, and what would it mean to do:

int i = 10;
win::cout << i << win::endl;

Would another window appear.. would it be a message box? would it be a window with menu, exit and just an edit control? Would the program halt execution?

There are probably resources that offer the windows (or windowing) equivalent of variables that support stdout - a paper on the subject at University level?

Perhaps I'm just being silly, and it could all be done with "new CWnd(.." in MFC.

Richard


February 19, 2003
What I do in such situations is I wrote my own printf() that just opened a log file, appended a line to it, and closed the file (this was so that even if the program crashed, the log file would be up to date). It works very well.


February 19, 2003
Try attached files... They might make your life easier.
Jan



Richard Grant wrote:

> Hi,
>
> I just finished a project in MFC, and everything was going smoothly right up until the end. Defining the interface with resource editor was easy, creating controls in code was trivial.. Using the Data Exchange to get access to the control data seemed a little contrived, but worked well. All in all a fairly complete application with minimal effort.
>
> Then I ran into an intermittent access violation. Ok, so I reached into my usual bag of tricks, and realized - how was I going to output program state using a windowing interface that was itself exhibiting problems. Rats. No std::cout to play with, and typed variables everywhere. Also the program was 3MB and my code couldn't have been more then 2 or 3 hundred lines.
>
> Anyway, after I finished stuffing MessageBox with stringstream managed strings, and dropping them into various places, I eventually found the problem. It looked like something to do with Thread Local Storage being instantiated improperly. I've worked with TLS before, so I looked around in the MFC code but gave up after about 10 seconds.
>
> I just restructured the code in places that seemed suspect: 1) using a static member function as control routine of AfxBeginThread, 2) having my own defined default c'tor and d'tor for theapp, 3) Passing the class of the static member function as the argument of the thread start, and casting from void to the class. And 4) starting the thread in oninitdialog instead of initializeapp. Everything seemed to work fine after that. Not that I thought what I was doing was illegal, just that they seemed like places the framework authors might get confused.
>
> The point is, I think I would have spent considerably more time trying to identify the problem if there were an iostream based variable like "win::cout" ("win" being a namespace qualifier). I did some minimum looking around, and was amazed that there was very little material on this issue. What with the continued success of Windowing environments, I would have thought that such a subject would have already been exhausted.
>
> I did find a macro at the Code Project "cout", but I hate macros - mostly due to the if (bool) macro; problem where the macro expands into more than one line. But that's really a personal distaste. Still, you get some typing and such, but I don't really like the format. I prefer to decide when a newline will appear, and what title to give my output. And why should I define the console?
>
> Since I don't program that often for GUI deployments, I am not certain what features win::cout would have, and what would it mean to do:
>
> int i = 10;
> win::cout << i << win::endl;
>
> Would another window appear.. would it be a message box? would it be a window with menu, exit and just an edit control? Would the program halt execution?
>
> There are probably resources that offer the windows (or windowing) equivalent of variables that support stdout - a paper on the subject at University level?
>
> Perhaps I'm just being silly, and it could all be done with "new CWnd(.." in MFC.
>
> Richard


February 19, 2003
In article <b2v3e1$1mr2$1@digitaldaemon.com>, Walter says...
>
>What I do in such situations is I wrote my own printf() that just opened a log file, appended a line to it, and closed the file (this was so that even if the program crashed, the log file would be up to date). It works very well.

Thanks. Yes that works very well, but its still somewhat discouraging since you don't get "tail -f" on windows. But perhaps there is a gnu utility.. I use something similiar for syslog/debuglog type behavior - it works well as of the recent DM C++ release (thanks again Walter and Christof for your efforts to get Stlport up to speed).

The following is just an example. As long as std::endl is used to flush the stream, the log file stays up to date. I'm sure Walter would find it useless for several reasons, and in multi-threaded applications there are also problems, but for me, it is an appwide syslog like construct that accepts complex types. In the example below, I usually have "util::System sys" defined in another file, and then make sure it becomes visible by requiring "util::sys.redirect(const std::string& logfileprefix)" before log start. Depending on the project, I also redirect clog and/or cout (usually to different files, hence logfileprefix above).

// redirect cerr to file example
#include <iostream>
#include <fstream>

namespace util {
class System {
public:
System() {
errfile = new std::ofstream("example.log");
std::streambuf* errbuf = errfile->rdbuf();
cerrbuf = std::cerr.rdbuf();
std::cerr.rdbuf(errbuf);
}
~System() {
std::cerr.rdbuf(cerrbuf);
delete errfile;
}
private:
System(const System& s) { }
System& operator=(const System& s) { return *this; }
std::ofstream* errfile;
std::streambuf* cerrbuf;
};

extern System sys;

} // util

util::System sys;

int main() {
std::cerr << "uh oh" << std::endl;
}

Richard


February 19, 2003
In article <3E53A0E5.AA4818EA@smartsoft.us>, Jan Knepper says...
>
>Try attached files... They might make your life easier.
>Jan

I can see you have had this problem before! Looking at your attachments, I can see that you have thought through the various types of information that might be required, and how it would effect program state to display that information (ie - stop the thread with messgebox, or continuous flow, etc.). The analysis of the problem demonstrated by your attachment is exactly what I was looking for. Thanks very much for sharing.

Richard


February 19, 2003
The problem, or alike problem are very common in software development... Quite a few of the systems  I have build are Real Time Systems... For initial testing may be you can do something with a debugger, but while the system is running full speed you would interrupt the flow with a debugger... Tracing like this L_TRACE variations with I used most work best... They have been implemented for Win32 and Unix...

Jan



Richard Grant wrote:

> In article <3E53A0E5.AA4818EA@smartsoft.us>, Jan Knepper says...
> >
> >Try attached files... They might make your life easier.
> >Jan
>
> I can see you have had this problem before! Looking at your attachments, I can see that you have thought through the various types of information that might be required, and how it would effect program state to display that information (ie - stop the thread with messgebox, or continuous flow, etc.). The analysis of the problem demonstrated by your attachment is exactly what I was looking for. Thanks very much for sharing.
>
> Richard

February 20, 2003
In article <3E54114F.197D3B0@smartsoft.us>, Jan Knepper says...
>
>The problem, or alike problem are very common in software development... Quite a few of the systems  I have build are Real Time Systems... For initial testing may be you can do something with a debugger, but while the system is running full speed you would interrupt the flow with a debugger... Tracing like this L_TRACE variations with I used most work best... They have been implemented for Win32 and Unix...

And thanks again. My original question was more oriented toward finding an already implemented windows output stream or creating a knowledge base for building a windows output stream for later use (should I need to make another GUI based project). And your material was absolutely right on.

I've noticed that for windows, there seems to be a general settling on using DebugOutA API and something like the SysInternals offering of DebugView to capture debug output at runtime. Then derive from basic_streambuf<> and associate that with an ostream to get good output behavior (from Rogue Wave materials). Another method comes from Dietmar Kuhl to derive behavior from streambuf to make a stream capable Motif Widget. Dietmar may also have submitted a windows based stream lib to the folks at boost, and I'm looking into that.

I like the use of streams in both underlying implementations, but frankly, I prefer your approach to determining "Where" the output will appear, or perhaps in stream language, the manipulators of the stream. And your TraceTitle is very innovative. In the end, I hope to create a variable like this one below.

namespace win {
extern windows_ostream<char> werr;
} // win

Stream manipulators could determine where the output appears. Perhaps something like:

int i = 99;
// message to tile bar.. win::show causes display in title bar
win::werr << win::win_base::title << "var is: " << i << win::show;
// message to DebugOutA.. win::show causes new line and flush
win::werr << win::win_base::debug << "var is: " << i << win::show;
// messagebox.. win::show causes display of message box
win::werr << win::win_base::msg << "var is: " << i << win::show;
// redirect to log file.
std::fstream logfile("c:\\file.log");
std::streambuf* file = logfile.rdbuf();
std::streambuf* s_werr = win::werr.rdbuf();
win::werr.rdbuf(file);
// output goes to file.log.. win::show causes newline and flush
win::werr << "var is: " << i << win::show;

I'm not sure it is wise to reuse the "c" based name win::cout, since even in namespace scope, cout/err/log are *very* reserved words, and some programmers are very much in the habit of doing "use namespace blah". So that requires some thought. I have used werr above. This may be effective since std::wcerr is so unused.

The redirection to a log file is such an integral part of the expectations of such a stream class, that it might be better to add a different layer than the manipulators. So that in addition to manipulator behavior, output could be directed to a log file and/or other targets:

int i = 99;
win::cdbg.logstart("c:\\file.log");
// below outputs to DebugOutA and c:\file.log
win::cdbg << win::win_base::debug << "var is: " << i << std::endl;
win::cdbg.logstop();
/ below outputs only to DebugOutA
win::cdbg << "var is: " << i << std::endl;

Also, while title (TraceTitle), logstart (TraceLog) and debug (new concept
TraceWindow) fit well into the output stream model, TraceMessage halts execution
of the program, and has other issues (such as potentially being an input
source). In fact, it could be argued that MessageBox is really the windows
equivalant of an input stream ala cin. I guess that requires more thought.

If you don't mind my asking, using your Macros, what approach do you take with regard to threading issues in the real time systems you have developed? I ask, becuase I imagine that simultaneous access to the same output medium might create a wait condition that effects the behavior of worker threads. Perhaps for TraceWindow and TraceFile you use different targets?

Richard