我是多线程编程的新手,我在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
相同。
据我所知,原子操作在被称为&#39;时是线程安全的。所以,是的,我认为我的代码是错的,但我无法弄清楚如何正常工作。
如何使用main
获得正确的结果?
(好吧,这个版本会让sum
和LIMIT
相等,但我认为这不是一个好方法......)
void foo(int idx) {
for (int i = 0; i < LIMIT / NUM_THREADS; i++) {
sum.fetch_add(1);
}
}
答案 0 :(得分:5)
正如在评论中所说,你的问题是变量在你加载它和你增加它的时间之间被另一个线程改变了。
您可以更改循环,例如像这样来解决它:
while (true) {
auto current = sum.load();
if (current >= LIMIT) {
return;
}
auto next = current + 1;
sum.compare_exchange_strong(current, next));
}
答案 1 :(得分:-1)
operator++
在原子类型上是原子的,所以你需要做的就是:
void foo(int idx) {
while (true) {
if (sum++ >= LIMIT) {
return;
}
}
}
一旦其中一个线程递增sum
到LIMIT
,其余线程也会看到该值大于或等于LIMIT
并返回。这里存在一个风险:如果线程数大于std::numeric_limits<int>::max() - LIMIT
,则后一个线程中的一个将增加sum
超过int
的最大值。只要LIMIT
是明智的&lt; g&gt;这不会是个问题。