首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >iostream线程安全,必须分别锁定cout和cerr吗?

iostream线程安全,必须分别锁定cout和cerr吗?
EN

Stack Overflow用户
提问于 2013-02-01 08:16:00
回答 3查看 8.9K关注 0票数 11

我知道,为了避免输出混合,多线程对cout和cerr的访问必须同步。在同时使用cout和cerr的程序中,单独锁定它们是否足够?或者同时写入cout和cerr仍然是不安全的?

编辑澄清:我知道cout和cerr在C++11中是“线程安全的”。我的问题是,不同线程同时对cout和cerr的写入是否会像两次对cout的写入那样相互干扰(导致交错输入等)。

EN

回答 3

Stack Overflow用户

发布于 2016-03-15 13:48:38

这里已经有了几个答案。我将总结并讨论它们之间的交互。

通常,

std::coutstd::cerr通常会集中到一个文本流中,因此在最有用的程序中,将它们锁定在一起会产生共同的结果。

如果忽略这个问题,coutcerr在默认情况下会作为它们的stdio对等项的别名,这些对等项是线程安全的as in POSIX,直到标准I/O函数(C++14§27.4.1/4,这比单独使用C更有保证)。如果您坚持选择这种函数,您会得到垃圾I/O,但不会得到未定义的行为(这是语言律师可能会将其与“线程安全”联系在一起,而不考虑其有用性)。

但是,请注意,尽管标准格式化I/O函数(例如读取和写入数字)是线程安全的,但用于更改格式的操作器(例如用于十六进制的std::hex或用于限制输入字符串大小的std::setw )不是线程安全的。因此,人们通常不能假设省略锁是安全的。

如果您选择单独锁定它们,事情会更加复杂。

单独锁定

为了提高性能,可以通过分别锁定coutcerr来减少锁争用。它们是单独缓冲(或不缓冲)的,它们可能会刷新到单独的文件中。

默认情况下,cerr会在每次操作之前刷新cout,因为它们是“绑定的”。这会破坏分离和锁定,所以记得在使用cerr.tie( nullptr )之前调用它。(这同样适用于cin,但不适用于clog。)

stdio解耦

该标准说,在coutcerr上的操作不会引入竞争,但这不是它的确切含义。流对象并不特殊;它们的底层streambuf缓冲区才是特殊的。

此外,调用std::ios_base::sync_with_stdio的目的是删除标准流的特殊方面-允许它们像其他流一样进行缓冲。尽管该标准没有提到sync_with_stdio对数据竞争的任何影响,但快速浏览一下libstdc++和libc++ (GCC和Clang) std::basic_streambuf类就会发现,它们不使用原子变量,因此在用于缓冲时,它们可能会创建竞争条件。(另一方面,libc++ sync_with_stdio实际上什么也不做,所以调用它也没关系。)

如果您希望在不考虑锁定的情况下获得额外的性能,那么sync_with_stdio(false)是一个好主意。然而,在这样做之后,锁定是必要的,如果锁是独立的,则还需要cerr.tie( nullptr )

票数 1
EN

Stack Overflow用户

发布于 2018-06-03 06:40:35

这可能是有用的;)

代码语言:javascript
复制
inline static void log(std::string const &format, ...) {
    static std::mutex locker;

    std::lock_guard<std::mutex>(locker);

    va_list list;
    va_start(list, format);
    vfprintf(stderr, format.c_str(), list);
    va_end(list);
}
票数 0
EN

Stack Overflow用户

发布于 2019-02-07 01:01:47

我使用的是这样的东西:

代码语言:javascript
复制
// Wrap a mutex around cerr so multiple threads don't overlap output
// USAGE:
//     LockedLog() << a << b << c;
// 
class LockedLog {
public:
    LockedLog() { m_mutex.lock(); }
    ~LockedLog() { *m_ostr << std::endl; m_mutex.unlock(); }

    template <class T>
    LockedLog &operator << (const T &msg)
    {
        *m_ostr << msg;
        return *this;
    }

private:
    static std::ostream *m_ostr;
    static std::mutex m_mutex;
};

std::mutex LockedLog::m_mutex;
std::ostream* LockedLog::m_ostr = &std::cerr;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14637595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档