我开始学习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却不会发生这种情况?

最佳答案

您没有显示您的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();
}));

09-10 04:44
查看更多