atomic streaming to cout

Hi,
I'm trying to implement an atomic ostream class.
It streams the data into an internal ostringstream buffer and writes the buffer as a single string to cout.
So I don't get messed up output when outputting from several threads (since a single streaming operation is atomic as far as I can remember).

This is what it should "look" like:
1
2
AtomicCout aCout;
aCout << 1 << "2" << '3' << someClassThatOverloadsTheStreamOperator; 


What I accomplished so far is that I can fill the internal ostringstream and print it during the destructor being executed.

I tried to define an operator void() for the class and thought it might get executed if the class ends up being in an void context. But it seams that this operator is never invoked.

This is was also works but is not as "beautiful"
1
2
3
4
{
    AtomicCout aCout;
    aCout << 1 << "2" << '3' << someClassThatOverloadsTheStreamOperator; 
}


1
2
AtomicCout aCout;
aCout << 1 << "2" << specialClassThatIssuesAtomicCoutToFlushItsBuffers; 


I also tried it with a temporary but the output is messed up if the first object to stream is a const char*:
 
AtomicCout() << "1" << 2;


I stepped through the program and found out that << "1" calls the function
_Myt& __CLR_OR_THIS_CALL operator<<(const void *_Val) (using Visual Studio 8.0) so const char* is converted to a const void* and therefore prints the address of the pointer I think.
But this doesn't happen if I don't use a temporary object.

And this also doesn't happen if I first stream in something else, like here:
 
AtomicCout() << 1 << "2";



This is the complete code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#pragma once
#include <sstream>
#include <iostream>

class AtomicWrite : public std::ostream
{
public:
   AtomicWrite();
  ~AtomicWrite();
  operator void();
private:
  std::ostringstream _os;
};

AtomicWrite::AtomicWrite()
: std::ostream(0)
, _os()
{
  this->init(_os.rdbuf());
}

AtomicWrite::~AtomicWrite()
{
  _os << '\n';
  std::cout << _os.str();
}

AtomicWrite::operator void()
{
  ; // just a breakpoint that get's never triggered...
}


I tested it with this code:
1
2
3
4
5
6
7
8
9
10
AtomicWrite() << "0" << 1 << 2.0 << '3' << "4";
AtomicWrite() << 0 << "1" << 2.0 << '3' << "4";
{
  AtomicWrite aw;
  aw << "0" << 1 << 2.0 << '3' << "4";
}
{
  AtomicWrite aw;
  aw << 0 << "1" << 2.0 << '3' << "4";
}


this was the output:
1
2
3
4
0048D6141234
01234
01234
01234

The same problems that apply to cout will also apply to your stringstream, synchronisation.

The use of AtomicWrite is a step forward, but it needs to buffer the writes from each thread and write the complete line when it receives endl.
std::ostream doesn't have an overloaded operator<<() that takes a const char *. That overload is global, so it won't get inherited by your class. You should implement it yourself.

As long as no instance of AtomicWrite is shared among threads and you lock the write on line 25, this should be thread safe.
@kbw: I don't think so. Since one instance of AtomicWrite will not be shared among threads, this should be fine.

@helios:
I thought there is a global function with this signature:
std::ostream& operator<<(std::ostream&, const char*)

This should work for my class since it's derived from ostream, shouldn't it?

And this still doesn't explain why it works in all cases except the temporary object and the const char* as the first argument!

UPDATE:
I just compiled it under VC10 and now it works. Seems to be a VC8 problem...

(since a single streaming operation is atomic as far as I can remember).


Is this even true? I find it somewhat hard to believe. Unless ostream internally is made to be threadsafe, which I doubt.
At the very least, VC++'s implementation makes each call to the operator<<() overload atomic. It's an extension, though, so you can't rely on it.

This should work for my class since it's derived from ostream, shouldn't it?
That's what I was thinking, but apparently the compiler is preferring the member. Otherwise you'd be entering the global overload instead of the member, when debugging.

By the way, suggestion:
1
2
3
4
5
6
7
8
9
10
11
12
//...
private:
    std::ostream &stream;
public:
    AtomicWrite(std::ostream &s=std::cout):stream(s){ /*...*/ }
    ~AtomicWrite(){
        _os << '\n';
        //lock
        this->stream << _os.str();
        //unlock
    }
//... 
I also googled a bit and found no one saying that's in the standard.
Especially if you queue your output with multiple <<'s.

Since I plan it just for logging purposes, the lock is not really necessary.
In a newer version I also removed the hard wired std::cout and am using a reference.
The lock only works if I also protect any other call to the stream referenced by stream with the lock.

I'm using VC++ and since I switched from
 
std::cout << now() << currentThread() << errormessage << '\n';

to
1
2
3
std::ostringstream oss;
oss << now() << currentThread() << errormessage << '\n';
std::cout << oss.str();


I'm not getting mixed up output anymore.
I'll keep it in mind that the atomic operator << is not dictated by the standard but implemented voluntarily by VC++ in case I switch the compiler...

Btw. the operator void() can never be called (except by explicitely writing AtomicWrite.operator void(), can it?
Since I plan it just for logging purposes, the lock is not really necessary.


But isn't the whole point of this class to make this operation threadsafe? How can you do that without a mutex?
At least in the 100.000+ lines of logs I produced, I didn't find a single mixed up line since I moved from streaming directly to streaming in a one stringstream per thread and then to the log file.

And if even if it would happen 1 in a 1000 lines that wouldn't be critical since since it's only read by humans.

I don't want the "working" threads to be blocked by the logging, that's why I don't use mutexes for this purpose.

If I would have to use this data in the program, I had to make sure this is really 100% threadsafe and use some kind of mutex.


Topic archived. No new replies allowed.