C++ 使用互斥量锁定流运算符

C++ Locking stream operators with mutex

我需要在我的日志记录应用程序中锁定 stdout,以防止在记录到 stdout 的多线程应用程序中出现字符串交错。无法弄清楚如何使用移动构造函数或 std::move 或其他方法将 unique_lock 移动到另一个对象。

我创建了用于设置配置和封装的对象,并弄清楚了如何使用静态 std::mutex 锁定标准输出以锁定这些对象(称为分片)。

像这样的东西对我有用:

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

虽然这很好并且可以使用模板和可变数量的参数来实现,但我想接近更多类似流的可能性。我正在寻找这样的东西:

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

我不想强迫用户通过连接预先计算字符串 to_string(42) 我只是想找到一种方法来锁定标准输出。

到目前为止,我的方法是创建运算符 << 和另一个对象锁定流,正如其他答案中所建议的那样。事情是我不知道如何将互斥体移动到另一个对象。我的代码:

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;
}

将输入输出到 std::cout 后,我想将锁移动到对象流中。

在这种情况下,我会小心不要在函数中使用静态锁,因为您会为您创建的每个流运算符获得不同的锁。

你需要的是在创建流时锁定一些"output lock",并在流销毁时解锁。如果您只是包装 std::ostream,则可以利用现有的流操作。这是一个有效的实现:

#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;
}

在 ideone 上:https://ideone.com/HezJBD

另外,请原谅,由于在线编辑的尴尬,上面会有空格和制表符的混合。