Baj*_*ile 1 c++ atomic c++11 stdthread visual-studio-2012
我想学习在 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;
}
Run Code Online (Sandbox Code Playgroud)
现在,当我仅使用 long long 变量(已注释)作为计数器时,我得到的值与正确的不同 - 100000000 而不是 200000000。我不知道为什么会这样,我想这两个线程正在改变计数器,但我不确定它是如何发生的,因为 ++ 只是一个非常简单的指令。似乎线程在开始时缓存 sum 变量。两个线程的性能为 110 毫秒,而一个线程的性能为 200 毫秒。
因此,根据文档,正确的方法是使用 std::atomic。然而,现在这两种情况的性能都要差得多,没有线程大约 3300 毫秒,有线程大约 15820 毫秒。在这种情况下使用 std::atomic 的正确方法是什么?
我不确定为什么会这样,我想两个线程同时更改计数器,但我不确定它是如何发生的,因为 ++ 只是一个非常简单的指令。
每个线程都将 的值拉sum入寄存器,递增寄存器,最后在循环结束时将其写回内存。
因此,根据文档,正确的方法是使用 std::atomic。然而,现在这两种情况的性能都要差得多,没有线程大约 3300 毫秒,有线程大约 15820 毫秒。在这种情况下使用 std::atomic 的正确方法是什么?
您正在为同步std::atomic提供的服务付费。它不会像使用非同步整数那么快,尽管您可以通过改进添加的内存顺序来获得性能的小幅改进:
sum.fetch_add(1, std::memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)
在这种特殊情况下,您正在为 x86 进行编译并在 64 位整数上进行操作。这意味着编译器必须生成代码来更新两个 32 位操作中的值;如果将目标平台更改为 x64,编译器将生成代码以在单个 64 位操作中执行增量。
一般来说,解决此类问题的方法是减少共享数据的写入次数。
| 归档时间: |
|
| 查看次数: |
2513 次 |
| 最近记录: |