Skip to main content
GameDev.net gamedev.net
🔒 Locked

Boost.Iostreams and multiple threads

Started by Codeka May 20, 2009 at 4:57 AM 0 replies 2.8k views
Original Post
Codeka
Codeka
I've written a logging system based on Boost.Iostreams (I wanted to add date/time information and other stuff to log messages automatically, so I wrote a sink class which I use with boost::iostreams::stream_buffer) but there's a problem with multiple threads trying to access the stream at once. My sink class looks like this:
class log_sink
{
private:
    std::string filename_;
    std::ofstream outs_;

public:
    typedef char char_type;
    typedef io::sink_tag category;

    log_sink(std::string const &filename);
    log_sink(log_sink const ©);

    std::streamsize write(const char* s, std::streamsize n);
};

log_sink::log_sink(std::string const &filename)
    : filename_(filename)
{
    outs_.open(filename_.c_str());
}

log_sink::log_sink(log_sink const ©)
    : filename_(copy._filename)
{
    outs_.open(filename_.c_str());
}

std::streamsize log_sink::write(const char *s, std::streamsize n)
{
    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();

    boost::lock_guard<boost::mutex> lock(mutex);
    outs_ << now << " : ";
    outs_.write(s, n);
    outs_.flush();

    return n;
}
I've then just got a global ostream, which I use like so:
boost::iostreams::stream_buffer<log_sink> debug_buffer;
std::ostream debug(&debug_buffer);

// ...

debug << "some stuff to write to the file" << std::endl;
Now, notice I use a boost::lock_guard<> in an attempt to prevent multiple threads from writing to the file at once. However, I think the problem is that the s pointer that is passed to the write function is pointing to a buffer that's shared between threads, so the lock doesn't really do much. I've had this problem for a while, and I never really bothered to look into it too much. But then I saw the recent Simple STL Logging article and I thought it might have had a solution. Unfortunately, the author basically got around the multi-threading problem by wrapping the whole "log << stuff" thing in a mutex, like this:
boost::mutex::scoped_lock lock(CLogger::log_mutex);
debug << "some stuff to write to the file" << std::endl;
lock.unlock();
Which I thought was a bit intrusive. I was thinking one way to do it would be to put my global stream object into thread-local storage and then sort out the multi-threading stuff inside my write function, pretty much like it already does. Is there a better way? This is really stretching my knowledge of Boost/SC++L :-)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.