代码之家  ›  专栏  ›  技术社区  ›  463035818_is_not_an_ai

是在C++98中编写单个字符串以实现“线程安全”

  •  3
  • 463035818_is_not_an_ai  · 技术社区  · 8 年前

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

    让我们说两个 pthreads 同时称之为:

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

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

    我问这个是因为 this question 让我好奇,我发现 this answer

    ... 在C++11中,std::cout是线程安全的。

    但是 this answer 介绍了一个沿以下路线的示例:

    std::cout << "aaaaaaaaaa" << "bbbbbbbbbb";
    

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

    1 回复  |  直到 8 年前
        1
  •  6
  •   BeeOnRope    8 年前

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

    然而,任何合理的C++98 实施 打算与线程一起使用(即,大多数线程在某些嵌入式市场之外)几乎肯定会提供至少或多或少的 安全 std::cout

    不幸的是,这差不多是你可以具体说的。特别要注意的是,我甚至 决定性的 以特定方式“安全”。至少你可能认为它不会崩溃,不会破坏你的程序,也不会“凭空”产生输出。除此之外,这还要视情况而定。

    这取决于什么

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

    通常,您会发现该实现具有一些与线程无关的代码(例如,复制到堆栈本地缓冲区),并在某些点锁定,然后在 对象何时何地锁定很重要。

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

    请记住,即使是 标准::cout operator<<(const char *) stdout 但通过一种机制,而不是 标准::cout -例如 printf() .

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

    多个运算符

    流接口的主要问题是多个运算符。类似于 std::cout << "AAA" << "BBB" ... 标准::cout 对象无需外部锁定,这些线程可以以任何方式与其他线程交错。关键是,这几乎意味着 iomanip 无法安全使用。类似于 std::cout << std::hex << 123 << std::dec 将全局修改流,以及其他一些不希望 hex 中间的 一次手术可能会产生一些奇怪、美妙或彻头彻尾的可怕结果。


    1.