C++ Locking stream operators with mutex

耗尽温柔 提交于 2019-12-24 00:26:00

问题


I need to lock stdout in my logging application to prevent string interleaving in multi-thread applications logging to stdout. Can't figure out how to use move constructor or std::move or sth else to move unique_lock to another object.

I created objects for setting configs and encapsulation and figured out how to lock stdout with static std::mutex to lock from these objects (called shards).

Something like this works for me:

l->log(1, "Test message 1");

While that is fine and could be implemented with templates and variable number of parameters I would like to approach more stream-like possibilities. I am looking for something like this:

*l << "Module id: " << 42 << "value: " << 42 << std::endl;

I dont want to force users to precompute string with concatenation and to_string(42) I just want to find a way to lock stdout.

My approach so far was to create operator << and another object locked stream, as was suggested in other answers. Things is I can't figure how to move mutex to another object. My code:

locked_stream& shard::operator<<(int num)
{
    static std::mutex _out_mutex;
    std::unique_lock<std::mutex> lock(_out_mutex);
    //std::lock_guard<std::mutex> lock (_out_mutex);
    std::cout << std::to_string(num) << "(s)";
    locked_stream s;
    return s;
}

After outputting input to std::cout I woould like to move lock into object stream.


回答1:


In this case, I would be careful not to use static locks in functions, as you will get a different lock for each stream operator you create.

What you need is to lock some "output lock" when a stream is created, and unlock it when the stream is destroyed. You can piggie back on existing stream operations if you're just wrapping std::ostream. Here's a working implementation:

#include <mutex>
#include <iostream>


class locked_stream
{
    static std::mutex s_out_mutex;

    std::unique_lock<std::mutex> lock_;
    std::ostream* stream_; // can't make this reference so we can move

public:
    locked_stream(std::ostream& stream)
        : lock_(s_out_mutex)
        , stream_(&stream)
    { }

    locked_stream(locked_stream&& other)
        : lock_(std::move(other.lock_))
        , stream_(other.stream_)
    {
        other.stream_ = nullptr;
    }

    friend locked_stream&& operator << (locked_stream&& s, std::ostream& (*arg)(std::ostream&))
    {
        (*s.stream_) << arg;
        return std::move(s);
    }

    template <typename Arg>
    friend locked_stream&& operator << (locked_stream&& s, Arg&& arg)
    {
        (*s.stream_) << std::forward<Arg>(arg);
        return std::move(s);
    }
};

std::mutex locked_stream::s_out_mutex{};

locked_stream locked_cout()
{
    return locked_stream(std::cout);
}

int main (int argc, char * argv[])
{
    locked_cout() << "hello world: " << 1 << 3.14 << std::endl;
    return 0;
}

Here it is on ideone: https://ideone.com/HezJBD

Also, forgive me, but there will be a mix of spaces and tabs up there because of online editors being awkward.



来源:https://stackoverflow.com/questions/36439373/c-locking-stream-operators-with-mutex

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!