Pietro
Pietro

Reputation: 13160

Output stream locking for multiprocess synchronisation?

Having multiple processes, all writing on the same output stream (e.g. with std::cout), is there a way to lock the stream so that, when a process starts writing his own message, it can do it till the end (e.g. with std::endl)?

I need a portable way of doing it.

Upvotes: 1

Views: 457

Answers (3)

reuben
reuben

Reputation: 3370

It's not clear if it would fit the parameters of your situation, but you could potentially funnel all data to a separate worker process that aggregates the data (with its own internal locking) before dumping them to stdout.

Upvotes: 2

jxh
jxh

Reputation: 70382

If you are on a UNIX like OS, then you may be able to mimic the behavior you want with a stringstream adapter. This may not be the best way to accomplish it, but the idea is to trigger a single write call whenever std::endl is encountered.

// Assume fd is in blocking mode
class fdostream : public std::ostringstream {
    typedef std::ostream & (*manip_t) (std::ostream &);
    struct fdbuf : public std::stringbuf {
        int fd_;
        fdbuf (int fd) : fd_(fd) {}
        int sync () {
            int r = ::write(fd_, str().data(), str().size());
            str(std::string());
            return (r > 0) ? 0 : -1;
        } 
    } buf_;
    std::ostream & os () { return *this; }
public:
    fdostream (int fd) : buf_(fd) { os().rdbuf(&buf_); }
};

fdostream my_cout(1);
my_cout << "Hello," << " world!" << std::endl;

This should achieve the effect of synchronized writes, at the cost of buffering input into a stringstream and then clearing the internal string after each flush.

For greater portability, you could modify the code to use fwrite, and specify unbuffered writes with setvbuf. But, the atomicity of fwrite would depend on the C implementation of the library function.

Upvotes: 1

wilx
wilx

Reputation: 18228

You are out of luck. You will have to use whatever your taget OS provides. This means using global/system-wide mutexes or lockf() like functions. You could use some 3rd party library to satisfy the portability requirement, like Boost.Interprocess.

Upvotes: 2

Related Questions