为什么std :: cout在线程中被抢占但是printf不是?

时间:2014-11-02 19:43:53

标签: c++ multithreading c++11

我开始学习C ++ 11标准中的线程,我正在尝试一个非常基本的程序,它创建10个线程,加入它们然后退出。在线程函数中,我尝试打印出我创建线程的for循环的索引,如下所示:

std::vector<std::thread> threads;
for(int i = 0; i < 10; i++)
{
    threads.push_back(std::thread([i](){ printf("Thread #%d\n", i); }));
}

这会产生一个预期来自并发程序的输出,线程不按顺序执行:

Thread #0
Thread #2
Thread #1
Thread #3
Thread #4
Thread #5
Thread #6
Thread #7
Thread #8
Thread #9

但是当我尝试使用std::coutstd::endl做同样的事情时,我明白了:

Thread #0
Thread #Thread #2
Thread #3
Thread #9
1
Thread #8
Thread #4
Thread #5
Thread #7
Thread #6

为什么会发生std::cout而不是printf呢?

2 个答案:

答案 0 :(得分:6)

您没有显示您的std :: cout代码。

threads.push_back(std::thread([i](){ printf("Thread #%d\n", i); }));

但如果我假设您将代码更改为:

threads.push_back(std::thread([i](){ std::cout << "Thread #" << i << std::endl; }));

两者有很大不同:

printf版本只能打印一个打印库。

printf("Thread #%d\n", i);

operator<<对打印库有三个不同的调用

operator<<(std::cout, "Thread #");
operator<<(std::cout, i);
operator<<(std::cout, std::endl);

// note for the pedantic the use of functions here is for illustration purposes.

假设打印库内部有某种锁定,printf版本将为每个线程提供一行。虽然operator<<版本可能会在通话之间被抢占。

即使有内部锁,我也不打赌任何版本。打印部分可能只是足够短,以至于观察中断的可能性很小,因此您可能还没有观察到它。

尝试:

threads.push_back(std::thread([i]()
{  std::stringstream msg;
   msg << "Thread #" << i << "\n";
   std::cout << msg.rdbuf();
}));

答案 1 :(得分:0)

据我所知,抢先行为无法保证让我假设您使用std :: endl结束std :: cout中的行。 std :: endl做了更多然后只是添加'\ n'它还刷新内部缓冲区,根据我的经验,这是一个线程之间受保护的操作。如果用'\ n'替换std :: endl,它也应该在线程之间混合输出。更进一步,如果你在你的std :: cout写了很长的行,你可能会强制缓冲区溢出,如果是std :: cout则刷新,在这种情况下输出也可能混淆。