假设我们有以下代码来计算出现事件的次数:
int i=0;
void f() {
// do stuff . . .
if(something_happens) ++i;
}
int main() {
std::vector<std::thread> threads;
for(int j = 0; j< std::thread::hardware_concurrency(); ++j) {
threads.push_back(std::thread(f));
}
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread_join));
std::cout << "i = " << i << '\n';
}
目前,i上有明显的竞争条件。使用C ++ 11,什么是(1)消除这种竞争条件的最简单方法,以及(2)最快的方法?,最好不使用互斥锁。感谢。
更新:使用注释来使用atomics,我得到了一个在英特尔编译器版本13下编译的工作程序:
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
#include <algorithm>
std::atomic<unsigned long long> i = 0;
void f(int j) {
if(j%2==0) {
++i;
}
}
int main() {
std::cout << "Atomic i = " << i << "\n";
int numThreads = 8; //std::thread::hardware_concurrency() not yet implemented by Intel
std::vector<std::thread> threads;
for(int k=0; k< numThreads; ++k) {
threads.push_back(std::thread(f, k));
}
std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
std::cout << "Atomic i = " << i << "\n";
}
答案 0 :(得分:16)
您可能需要查看atomic types。您可以在不需要锁/互斥锁的情况下访问它们。
答案 1 :(得分:3)
我们通过声明一个数组[nThreads]解决了类似的问题,然后我们为每个线程提供了一个范围从0-n的id,然后该线程可以安全地写入它在数组中的位置。然后你可以将数组相加得到总和。然而,这只是有用的,只要你不需要在所有线程都死之前对数组求和。
为了更高效,我们在每个线程上都有一个本地计数器,然后我们在线程死亡之前附加到数组。
示例(伪代码:)
counter[nThreads];
thread(int id)
{
// Do stuff
if(something happened)
counter[id]++;
}
或
counter[nThreads];
thread(int id)
{
int localcounter = 0;
//Do stuff
if(something happened)
localcounter++;
//Thread is about to die
counter[id] = localcounter;
}
答案 2 :(得分:1)
您可以使用InterlockedIncrement功能。
MSDN在Synchronization Functions的标语下记录了许多以原子方式改变变量的函数 - 它们可能对您有用。
答案 3 :(得分:1)
这不仅仅是一种竞争条件,如果您的编译器决定,您可能根本没有在线程之间传递实际的i
值。
显然atomic
是好方法。互斥也是一种好方法,当你没有碰撞时,它们就像原子一样快。只有当他们真正需要使内核与sleeping
和ready
线程队列混合时,它们才会变慢。可以获得taxy的是,如果等待信号没有使用condition variable
,在这种情况下,您可能必须等待ready
线程的计划内核标记为running
,这可以很长(30ms)。
atomics会让你获得最优,甚至可能比condition variable
更容易维护,这要归功于不必关心spurious
事件和notify_one
与notify_all
等
如果检查C ++ 11制造的STL的shared_ptr基类,它们包含base_count
或(base_shared_count或其他),它们的工作方式完全符合您的需要。
如果愿意,您也可以检查新的boost :: shared_count实现。