【问题标题】:C++ Locking stream operators with mutexC ++使用互斥锁锁定流运算符
【发布时间】:2016-07-26 03:53:30
【问题描述】:

我需要在我的日志记录应用程序中锁定标准输出,以防止多线程应用程序中的字符串交错记录到标准输出。无法弄清楚如何使用移动构造函数或 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 后,我​​想将锁移到对象流中。

【问题讨论】:

  • 不确定评论是否会受到赞赏,但在这种情况下我会做的是将日志记录卸载到另一个线程。日志线程将在没有任何锁的情况下写入标准输出,而其他线程可以通过无锁队列发送消息。更少的争用和更高的吞吐量,并且不需要通过流操作编织锁。无论如何我都会添加答案。
  • 我很感激!我将尝试合并您的答案和现有代码,但会牢记您的建议!以后还不如试着改写。

标签: multithreading c++11 logging stdout mutex


【解决方案1】:

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

您需要的是在创建流时锁定一些“输出锁”,并在流被销毁时解锁。如果您只是包装 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

另外,请原谅我,但由于在线编辑器很尴尬,上面会有空格和制表符混合在一起。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-10
    • 2022-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多