为什么std::cout在线程中被抢占,而printf却没有
Why is std::cout preempted in a thread but printf is not?
我开始学习C++11标准中的线程,我正在尝试一个非常基本的程序,该程序创建10个线程,连接它们,然后退出。在线程函数中,我试图打印出我正在创建线程的for循环的索引,如下所示:
std::vector<std::thread> threads;
for(int i = 0; i < 10; i++)
{
threads.push_back(std::thread([i](){ printf("Thread #%dn", i); }));
}
这会产生一个预期来自并发程序的输出,线程执行顺序错误:
Thread #0
Thread #2
Thread #1
Thread #3
Thread #4
Thread #5
Thread #6
Thread #7
Thread #8
Thread #9
但是,当我尝试使用std::cout
和std::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 #%dn", i); }));
但如果我假设你把代码改成:
threads.push_back(std::thread([i](){ std::cout << "Thread #" << i << std::endl; }));
两者有很大的不同:
printf
版本只有一个对打印库的调用
printf("Thread #%dn", 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
版本将为每个线程提供一行。而CCD_ 8版本可能在调用之间被抢占。
我不会打赌任何版本都有内部锁。打印部分可能很短,观察到中断的可能性很小,因此您可能还没有观察到。
尝试:
threads.push_back(std::thread([i]()
{ std::stringstream msg;
msg << "Thread #" << i << "n";
std::cout << msg.rdbuf();
}));
据我所知,抢占行为并不能得到保证。让我假设您用std::endl结束std::cout中的行。std::endl所做的不仅仅是添加'\n',它还刷新内部缓冲区,根据我的经验,这是线程之间受保护的操作。如果将std::endl替换为'\n',它还应该混合线程之间的输出。此外,如果在std::cout中写入很长的行,则可能会强制缓冲区溢出和刷新,如果std::cout和在这种情况下输出也可能混淆。
相关文章:
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- C++ Setter/Getter,cout 工作,printf 失败
- 0x%08lx 格式说明符在 printf 语句到 cout
- cout 打印不准确的结果,printf 打印准确的结果
- 为什么 printf 在 C++ 中的执行速度比 cout 快?另外scanf比cin慢,为什么?
- C++, printf vs cout performance
- printf() 和 std::cout 在指针方面的区别
- C++将printf更改为cout
- 为什么printf会导致与future.get的死锁,而cout则不会?
- 为什么printf和cout为此无符号int提供了不同的输出
- 为什么在 c++ 中使用 ios::sync_with_stdio(false) 后在 cout 之前执行 printf
- 在CPP的COUT中等效的printf格式
- printf 整数显示超过 C++ cout
- 为什么 CIN / COUT 比 scanf/printf 慢
- 要在不使用cout的情况下打印某些内容,请使用printf或puts()
- 执行叉()时cout vs printf
- 如何将COUT/CINS转换为printf/scanfs
- 将printf语句转换为cout
- 从printf-复杂格式指定符模式切换到cout
- 如何通过JNI/NDK获得Android应用中使用的c++库的日志行(printf, cout等)的控制台输出