Tob*_*ull 8 concurrency mutex c++11 stdthread
编译以下代码时
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include <mutex>
std::mutex cout_mut;
void task()
{
for(int i=0; i<10; i++)
{
double d=0.0;
for(size_t cnt=0; cnt<200000000; cnt++) d += 1.23456;
std::lock_guard<std::mutex> lg(cout_mut);
std::cout << d << "(Help)" << std::endl;
// std::cout << "(Help)" << d << std::endl;
}
}
int main()
{
std::vector<std::thread> all_t(std::thread::hardware_concurrency());
auto t_begin = std::chrono::high_resolution_clock::now();
for(auto& t : all_t) t = std::thread{task};
for(auto& t : all_t) t.join();
auto t_end = std::chrono::high_resolution_clock::now();
std::cout << "Took : " << (t_end - t_begin).count() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在MinGW 4.8.1下,我的盒子上执行大约需要2.5秒.这大约只是task单线程执行函数所需的时间.
但是,当我取消注释中间的行并因此注释掉之前的行(也就是说,当我交换其中的订单d并被"(Help)"写入时std::cout)时,整个过程需要8-9秒.
解释是什么?
我再次测试,发现我只有MinGW-build的问题x32-4.8.1-win32-dwarf-rev3但没有MinGW构建x64-4.8.1-posix-seh-rev3.我有一台64位机器.使用64位编译器,两个版本都需要三秒钟.但是,使用32位编译器时,问题仍然存在(并且不是由于发布/调试版本混淆).
它与多线程无关。这是一个循环优化问题。我重新排列了原始代码,以获得一些简约的方式来演示该问题:
#include <iostream>
#include <chrono>
#include <mutex>
int main()
{
auto t_begin = std::chrono::high_resolution_clock::now();
for(int i=0; i<2; i++)
{
double d=0.0;
for(int j=0; j<100000; j++) d += 1.23456;
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
#ifdef SLOW
std::cout << 'a' << d << std::endl;
#else
std::cout << d << 'a' << std::endl;
#endif
}
auto t_end = std::chrono::high_resolution_clock::now();
std::cout << "Took : " << (static_cast<double>((t_end - t_begin).count())/1000.0) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
编译并执行时并使用:
g++ -std=c++11 -DSLOW -o slow -O3 b.cpp -lpthread ; g++ -std=c++11 -o fast -O3 b.cpp -lpthread ; ./slow ; ./fast
Run Code Online (Sandbox Code Playgroud)
输出是:
a123456
a123456
Took : 931
123456a
123456a
Took : 373
Run Code Online (Sandbox Code Playgroud)
时序上的大部分差异可以通过为内部循环生成的汇编代码来解释:快速情况直接累加到 xmm0 中,而慢速情况累加到 xmm1 中 - 导致 2 个额外的 movsd 指令。
现在,当使用“-ftree-loop-线性”选项编译时:
g++ -std=c++11 -ftree-loop-linear -DSLOW -o slow -O3 b.cpp -lpthread ; g++ -std=c++11 -ftree-loop-linear -o fast -O3 b.cpp -lpthread ; ./slow ; ./fast
Run Code Online (Sandbox Code Playgroud)
输出变为:
a123456
a123456
Took : 340
123456a
123456a
Took : 346
Run Code Online (Sandbox Code Playgroud)