为什么cout不能与pthread一起使用?

4
我正在尝试编写一个简单的程序测试多线程。我只是在交替的线程中打印一系列“x”和“O”。现在,如果我使用cout,屏幕上看不到输出。如果我使用fputc并将输出发送到stderr,它就可以正常工作。为什么在这里使用cout(输出到stdout)不起作用?
我的代码如下:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

using namespace std;

static int count;

void* print_xs(void *unused)
{
    while(1)
    {
        if (count >=100) break;
        if (count%2==0)
        {
            count++;
            cout<<"X=";  // no output here
            fputc('X',stderr); // works !
        }
        else
        {
            sleep(1);
        }
    }
    return NULL;

}


int main()
{
    pthread_t tid;
    pthread_create(&tid,NULL,&print_xs, NULL);

    while(1)
    {
        if (count >=100) break;
        if (count%2!=0)
        {
            count++;
            cout<<"O="; // no output here 
            fputc('O',stderr); // works !
        }
        else
        {
            sleep(1);
        }
    }

    pthread_join(tid,NULL);
    return (0);

}

6
你尝试过使用 flush 刷新 std::cout 吗? - Jarod42
1
尝试将输出打印到“标准输出”(stdout)而不是其他地方。 - Some programmer dude
2
@Nawaz std::cout是线程安全的。 - Galik
@Galik:是的,自从C++11之后它已经改变了。感谢您的纠正。 - Nawaz
还有:你的代码在我的电脑上运行正常(Linux GCC 6.1.1)。 - Galik
可能是Is cout synchronized/thread-safe?的重复问题。 - jww
1个回答

1
std::cout 是一个缓冲流,因此需要 刷新 它才能将缓冲区发送到标准输出。
只需尝试如下操作:
cout<< "O=";
cout.flush();

那应该可以工作。

附加说明

  1. 正如一些评论已经建议你的那样,在C++03及之前,std::cout不是线程安全的。使用mutex来保护该对象可能很有用。这在C++11标准中可能不是问题。

FDIS在§27.4.1 [iostream.objects.overview]中说:

在多个线程中对同步(§27.5.3.4)的标准iostream对象的格式化和未格式化输入(§27.7.2.1)和输出(§27.7.3.1)函数或标准C流的并发访问不应导致数据竞争(§1.10)。[注意:如果用户希望避免交错的字符,则仍必须通过多个线程同步并发使用这些对象和流。—注]

这意味着在数据竞争的情况下,没有互斥锁也可以保证对象不会被破坏。但是,重叠输出的问题仍然存在。因此,如果您确定每行都没有被其他线程覆盖打印,仍需要互斥锁。
C++11引入了一个多线程库(通常是对pthread的包装)。这里有一些参考资料。只需看一眼,您可能会发现它很有用。

谢谢,但我不明白为什么只有在使用线程时才会出现这个问题?当我正常使用cout时,它可以正确地显示在stdout上。 - vinit
这不是真的。即使在单线程中,你也会得到那种行为。我想你从未注意到过。我刚刚写了一段简单的代码,打印了10次字符串(*没有\n*):for(...) std::cout << "something";,然后用调试器跟踪,直到程序结束都没有任何输出。(你也可以尝试一下,但这取决于特定的实现方式)。如果需要,我还可以修改我的答案并展示给你那种行为。 - BiagioF
@vinit 我忘记标记你了 :) - BiagioF
我明白了,所以cout一直缓冲直到遇到'\n'或刷新?谢谢,我不知道这个....在C++中总会有新东西要学习 :) - vinit
1
@vinit 实际上,当遇到 '\n' 时,并没有保证流被刷新。这就是为什么 std::endl 插入新行字符 '\n' 并刷新流的原因。如果您愿意,可以将答案标记为正确。 - BiagioF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接