I want to implement a simple class for logging from multiple threads. The idea there is, that each object that wants to log stuff, receives an ostream-object that it can write messages to using the usual operators. The desired behaviour is, that the messages are added to the log when the stream is flushed. This way, messages will not get interrupted by messages from other threads. I want to avoid using a temporary stringstream to store the message, as that would make most messages at least twoliners. As I see it, the standard way of achieving this would be to implement my own streambuffer, but this seems very cumbersome and error-prone. Is there a simpler way to do this? If not, do you know a good article/howto/guide on custom streambufs?
Thanks in advance,
Space_C0wbo0y
UPDATE:
Since it seems to work I added my own answer.
In the simplest of terms threadsafe means that it is safe to be accessed from multiple threads. When you are using multiple threads in a program and they are each attempting to access a common data structure or location in memory several bad things can happen. So, you add some extra code to prevent those bad things.
thread-safety or thread-safe code in Java refers to code that can safely be utilized or shared in concurrent or multi-threading environment and they will behave as expected.
The logging module can be used directly from multiple threads. The reason is because the logging module is thread-safe. The logging module is intended to be thread-safe without any special work needing to be done by its clients. — Thread Safety, logging — Logging facility for Python.
Yes, ILogger s in Serilog are always safe to use concurrently from multiple threads.
Take a look at log4cpp; they have a multi-thread support. It may save your time.
So, I took a look at Boost.IOstreams and here's what I've come up with:
class TestSink : public boost::iostreams::sink {
public:
std::streamsize write( const char * s, std::streamsize n ) {
std::string message( s, n );
/* This would add a message to the log instead of cout.
The log implementation is threadsafe. */
std::cout << message << std::endl;
return n;
}
};
TestSink
can be used to create a stream-buffer (see stream_buffer-template). Every thread will receive it's own instance of TestSink
, but all TestSinks
will write to the same log. TestSink
is used as follows:
TestSink sink;
boost::iostreams::stream_buffer< TestSink > testbuf( sink, 50000 );
std::ostream out( &testbuf );
for ( int i = 0; i < 10000; i++ )
out << "test" << i;
out << std::endl;
The important fact here is, that TestSink.write
is only called when the stream is flushed (std::endl
or std::flush
), or when the internal buffer of the stream_buffer
instance is full (the default buffer size cannot hold 40000 chars, so I initalize it to 50000). In this program, TestSink.write
is called exactly once (the output is too long to post here). This way I can write logmessage using normal formatted stream-IO without any temporary variables and be sure, that the message is posted to the log in one piece when I flush the stream.
I will leave the question open another day, in case there are different suggestions/problems I have not considered.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With