找出std :: ostream&是否指向全局对象

问题描述 投票:2回答:2

如果采用以下方法

template<typename... Args>
void report(std::ostream&str, Args&&... args)
{
    (str << ... << args);
}

从具有相同str的不同线程同步调用,来自不同线程的写入可能被破坏。因此,我改用

template<typename... Args>
void report(std::ostream&str, Args&&... args)
{
    std::ostringstream ostr;
    (ostr << ... << args);
    str << ostr.str();
}

现在,我想知道是否有可能检测到这是否确实是必要的,即

{
    if(is_global_object(str)) {      // how to implement this?
        std::ostringstream ostr;
        (ostr << ... << args);
        str << ostr.str();
    } else
        (str << ... << args);
}

问题:如何实施is_global_object(str)?我很乐意发现所有的std::coutstd::wcoutstd::clogstd::wclogstd::cerrstd::wcerr

c++ output outputstream
2个回答
3
投票

不,绝对不可能。如果一个线程创建一个本地ostream然后将引用传递给另一个线程怎么办?不是全球性的,但仍然是共享的对象的全局性并不决定其位置。


1
投票

首先,没有办法检查某个引用是否是对全局对象的引用。至少没有一些硬平台特定的黑客攻击(静态内存扫描?)可能无法正常工作。不要走那条路。

其次(更重要的是)你的问题不是“全球性的”。它是“共享的”。为什么您认为变量必须是全局的才能共享?另一方面,可能存在不共享的全局变量。但无论如何,这也没有解决方案。没有黑客会帮助你。

第三,您的中间代码也不是线程安全的。无法保证单个写入必须是线程安全的。在某些情况下,它是(std :: cout),但std :: ostream没有这样的保证。我可以使用非线程安全写入轻松编写自己的流。

最后但并非最不重要的是,您可以通过利用类和互斥体来避免所有这些。像这样的东西:

class Logger {
    public:
        Logger(std::ostream& stream): stream {stream}
        {};

        template<typename... Args>
        void log(Args&&... args)
        {
            std::lock_guard<std::mutex> lg {mu};
            (stream << ... << args);
        }

    private:
        std::ostream& stream;
        std::mutex mu;
};

并且根本不担心所有线程安全。

为了更好地扩展,您可能需要查看一些无锁的消息排队。

© www.soinside.com 2019 - 2024. All rights reserved.