【发布时间】:2015-03-04 00:24:53
【问题描述】:
我想学习在 VS2012 中使用 C++ 11 std::threads,我编写了一个非常简单的 C++ 控制台程序,它有两个线程,它们只是增加一个计数器。我还想测试使用两个线程时的性能差异。测试程序如下:
#include <iostream>
#include <thread>
#include <conio.h>
#include <atomic>
std::atomic<long long> sum(0);
//long long sum;
using namespace std;
const int RANGE = 100000000;
void test_without_threds()
{
sum = 0;
for(unsigned int j = 0; j < 2; j++)
for(unsigned int k = 0; k < RANGE; k++)
sum ++ ;
}
void call_from_thread(int tid)
{
for(unsigned int k = 0; k < RANGE; k++)
sum ++ ;
}
void test_with_2_threds()
{
std::thread t[2];
sum = 0;
//Launch a group of threads
for (int i = 0; i < 2; ++i) {
t[i] = std::thread(call_from_thread, i);
}
//Join the threads with the main thread
for (int i = 0; i < 2; ++i) {
t[i].join();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
chrono::time_point<chrono::system_clock> start, end;
cout << "-----------------------------------------\n";
cout << "test without threds()\n";
start = chrono::system_clock::now();
test_without_threds();
end = chrono::system_clock::now();
chrono::duration<double> elapsed_seconds = end-start;
cout << "finished calculation for "
<< chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms.\n";
cout << "sum:\t" << sum << "\n";\
cout << "-----------------------------------------\n";
cout << "test with 2_threds\n";
start = chrono::system_clock::now();
test_with_2_threds();
end = chrono::system_clock::now();
cout << "finished calculation for "
<< chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms.\n";
cout << "sum:\t" << sum << "\n";\
_getch();
return 0;
}
现在,当我将 long long 变量(已注释)用于计数器时,我得到的值与正确的值不同 - 100000000 而不是 200000000。我不确定为什么会这样,我想这两个线程正在同时更改计数器,但我不确定它是如何发生的,因为 ++ 只是一个非常简单的指令。似乎线程在一开始就缓存了 sum 变量。两个线程的性能为 110 毫秒,而一个线程的性能为 200 毫秒。
所以根据文档正确的方法是使用std::atomic。然而,现在这两种情况的性能要差得多,大约 3300 ms 没有线程,15820 ms 有线程。在这种情况下使用 std::atomic 的正确方法是什么?
【问题讨论】:
-
你是在 Release 模式下编译吗?
-
没有原子,你的程序会有未定义的行为。使用原子,它会更慢,因为您现在有两个线程一直在争夺同一个变量。多线程非常昂贵,只有在某些特殊情况下才值得。
-
即使没有线程也慢得多。我还有什么其他选择可以让它正确快速地工作?
-
VS2012 也有一个相当低效的
std::atomic实现。 VS2013 好很多。 -
用
sum += RANGE;和atomic替换循环,性能几乎没有那么重要。并发的一般规则是最小化争用,而不是毫无意义地最大化它。
标签: c++ c++11 visual-studio-2012 atomic stdthread