c++ - 在 C++98 中将单个字符串写入 cout "thread safe"

标签 c++ multithreading c++98

我知道严格来说在 C++98 中没有什么是线程安全的,因为在 C++11 之前的标准中没有线程。然而,在实践中,线程早在 C++11 之前就已在 C++ 中使用。

让我们说两个 pthreads同时调用这个:

void printSomething(){
    std::cout << "something\n";
}

什么会导致两个输出交错?或者我会在实践中总是得到包含“某物”的两行吗?

我问这个是因为 this question让我想知道,我发现了this answer说明:

... in C++11, std::cout is thread-safe.

但是this answer沿着

的方向展示了一个例子
std::cout << "aaaaaaaaaa" << "bbbbbbbbbb";

并得出结论,在 C++98 中,执行此操作的两个线程可能会交错输出,但我找不到任何关于调用 operator<< 的两个线程的信息。只有一次。

最佳答案

正如评论中指出的那样,C++98 在标准中没有提供任何线程的概念,因此您不能通过引用标准来回答这个问题。

然而,任何旨在与线程一起使用的合理 C++98 实现(即,大多数在某些嵌入式市场之外)几乎肯定会提供至少或多或少的 安全 std::cout对于“普通”用例。毕竟,使用该流进行输出非常普遍,在线程程序中跨线程使用它也将非常普遍。

不幸的是,您只能说这么多。请特别注意,我什至没有以特定方式定义“安全”。至少您可能期望它不会崩溃、损坏您的程序或“凭空”产生输出。除此之外,这取决于。

它取决于什么

下一步是检查实现本身。希望你有来源1!

通常你会发现实现有一些线程不可知的代码(例如,复制到堆栈本地缓冲区)并且在某些时候锁定然后操作 std::cout 内的共享状态。目的。何时何地锁定很重要。

单字符串

例如,我们希望单个项目在两个线程上的输出,如 std::cout << "AAAA"在线程 1 和 std::cout << "BBBB" 上在线程 2 上至少会导致 AAAABBBB 的“非交错”输出或 BBBBAAAA但从来没有 BBAAAABB或类似的东西。对于以某些方式缓冲的实现,这可能不正确!例如,实现可能会锁定,然后尽可能多地复制到内部缓冲区中,如果已满,则输出,然后解锁并再次进行。

请记住,即使是 std::cout对象被完全锁定(即,基本上整个 operator<<(const char *) 在锁下运行),当它与正在写入 stdout 的其他代码同时运行时,您可能会看到甚至单个字符串输出的交错。但通过 std::cout 以外的机制- 例如 printf() .

在这种情况下,C/C++ 运行时通常不会共享任何锁,您将依赖底层 write() 的锁。 -操作系统提供的类型调用。尽管此调用是完全锁定且线程安全的,但它可能不会一次性写入整个字符串(这很常见,例如,当中间缓冲区填满时,例如 writing to a pipe )。

多个运算符

流接口(interface)的主要问题是多个运算符。类似于 std::cout << "AAA" << "BBB" ...几乎总是变成对共享 std::cout 的多次调用目的。在您没有外部锁定的情况下,这些线程可以以任何方式与其他线程自由交错。至关重要的是,这几乎意味着 iomanip 中的流操纵器不可能安全使用。类似于 std::cout << std::hex << 123 << std::dec将全局修改流,以及一些不需要 hex 的其他线程输出可能会在错误的时间运行并且无论如何都会得到它。此外,流格式化状态和标志可以在操作的中间改变这一事实可能会产生一些奇怪的、美妙的或彻头彻尾的可怕结果。


1 当然,该源可用于开源运行时,如 libstc++(由 gcc 使用)和 libc++(在大多数非 Linux 平台上默认由 LLVM 使用)。 Microsoft 似乎也在为其 C 运行时提供源代码。

关于c++ - 在 C++98 中将单个字符串写入 cout "thread safe",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46819052/

相关文章:

multithreading - 我不懂多线程编程

java - Swing 动画运行速度极慢

c++ - std::size_t 与 size_type 作为参数和函数返回类型

c++ - 前向声明和 shared_ptr

c++ - 在 std::vector 中实例化对象时出现错误 C2280/复制构造函数问题?

c++ - 之后如何为 std::async 修改 std::launch 策略?

语言规范中的Java静态初始化线程安全保证

c++ - 如何避免多态和 vector 的内存泄漏?

c++ - 插入排序问题?

c++ - 根据 cmake 目标启用宏