如何正确增加 C++11 std::atomic?
How can I properly increase C++11 std::atomic?
我是多线程编程的新手,我发现了 C++11 中的 std::atomic
。
所以,我试图弄清楚原子操作需要多少时间。
我试过这段代码:
using namespace std;
using namespace std::chrono;
constexpr int NUM_THREADS = 8;
constexpr int LIMIT = 100000;
atomic<int> sum = 0;
void foo(int idx) {
while (true) {
if (sum.load() >= LIMIT) {
return;
}
sum.fetch_add(1);
}
}
与 main
:
int main(void) {
thread threads[NUM_THREADS];
auto start = high_resolution_clock::now();
for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = thread(&foo, i);
}
for (int i = 0; i < NUM_THREADS; i++) {
threads[i].join();
}
auto du = high_resolution_clock::now() - start;
cout << "computing time\t\t" << duration_cast<milliseconds>(du).count() << "ms" << endl;
cout << "number of thread\t" << NUM_THREADS << endl;
cout << "sum\t\t\t" << sum << endl;
return 0;
}
但 sum
并不总是与 LIMIT
相同。
据我所知,原子操作在 'called' 时是线程安全的。所以,是的,我认为我的代码是错误的,但我不知道如何让它正常工作。
我怎样才能得到正确的结果main
?
(好吧,这个版本会让 sum
和 LIMIT
相等,但我认为这不是一个好方法...)
void foo(int idx) {
for (int i = 0; i < LIMIT / NUM_THREADS; i++) {
sum.fetch_add(1);
}
}
正如评论中所说,您的问题是变量在您加载它的时间和您递增它的时间之间被另一个线程更改。
您可以更改循环,例如像这样修复它:
while (true) {
auto current = sum.load();
if (current >= LIMIT) {
return;
}
auto next = current + 1;
sum.compare_exchange_strong(current, next));
}
operator++
在原子类型上是原子的,所以你需要做的就是:
void foo(int idx) {
while (true) {
if (sum++ >= LIMIT) {
return;
}
}
}
一旦其中一个线程将 sum
递增到 LIMIT
,其余线程也会看到该值大于或等于 LIMIT
和 return.这里存在一个风险:如果线程数大于 std::numeric_limits<int>::max() - LIMIT
,那么后面的线程之一将递增 sum
超过 int
的最大值。只要 LIMIT
是明智的 这将不是问题。
我是多线程编程的新手,我发现了 C++11 中的 std::atomic
。
所以,我试图弄清楚原子操作需要多少时间。
我试过这段代码:
using namespace std;
using namespace std::chrono;
constexpr int NUM_THREADS = 8;
constexpr int LIMIT = 100000;
atomic<int> sum = 0;
void foo(int idx) {
while (true) {
if (sum.load() >= LIMIT) {
return;
}
sum.fetch_add(1);
}
}
与 main
:
int main(void) {
thread threads[NUM_THREADS];
auto start = high_resolution_clock::now();
for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = thread(&foo, i);
}
for (int i = 0; i < NUM_THREADS; i++) {
threads[i].join();
}
auto du = high_resolution_clock::now() - start;
cout << "computing time\t\t" << duration_cast<milliseconds>(du).count() << "ms" << endl;
cout << "number of thread\t" << NUM_THREADS << endl;
cout << "sum\t\t\t" << sum << endl;
return 0;
}
但 sum
并不总是与 LIMIT
相同。
据我所知,原子操作在 'called' 时是线程安全的。所以,是的,我认为我的代码是错误的,但我不知道如何让它正常工作。
我怎样才能得到正确的结果main
?
(好吧,这个版本会让 sum
和 LIMIT
相等,但我认为这不是一个好方法...)
void foo(int idx) {
for (int i = 0; i < LIMIT / NUM_THREADS; i++) {
sum.fetch_add(1);
}
}
正如评论中所说,您的问题是变量在您加载它的时间和您递增它的时间之间被另一个线程更改。
您可以更改循环,例如像这样修复它:
while (true) {
auto current = sum.load();
if (current >= LIMIT) {
return;
}
auto next = current + 1;
sum.compare_exchange_strong(current, next));
}
operator++
在原子类型上是原子的,所以你需要做的就是:
void foo(int idx) {
while (true) {
if (sum++ >= LIMIT) {
return;
}
}
}
一旦其中一个线程将 sum
递增到 LIMIT
,其余线程也会看到该值大于或等于 LIMIT
和 return.这里存在一个风险:如果线程数大于 std::numeric_limits<int>::max() - LIMIT
,那么后面的线程之一将递增 sum
超过 int
的最大值。只要 LIMIT
是明智的