C++ 在C+;中实现共享整数计数器的最简单方法+;11没有互斥体:

C++ 在C+;中实现共享整数计数器的最简单方法+;11没有互斥体:,c++,multithreading,c++11,stdatomic,C++,Multithreading,C++11,Stdatomic,假设我们有以下代码,用于计算发生事件的次数: 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(

假设我们有以下代码,用于计算发生事件的次数:

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';
}
inti=0;
void f(){
//做些事情。
如果(发生了什么事)+i;
}
int main(){
向量线程;
对于(int j=0;j

MSDN上记录了许多以原子方式变异变量的函数,其标题为-它们可能对您有用。

您可能需要研究它们。您无需锁/互斥即可访问它们。

我们通过声明数组[n读取]解决了类似的问题,然后我们给每个线程一个范围为0-n的id,线程可以在其在数组中的位置安全地写入。然后,您可以对数组求和以获得总和。但是,只要您不需要在所有线程都死掉之前对数组求和,这才有帮助

为了提高效率,我们在每个线程上都有一个本地计数器,然后在线程死之前将其附加到数组中

示例(伪代码:)


这不仅仅是一个竞争条件,如果编译器决定这样做,那么线程之间可能根本就没有实际的
i
值的通信

显然,
atomic
是一种好方法。互斥也是一种好方法,在没有冲突的情况下,它们与原子一样快。只有在实际需要让内核处理
休眠
就绪
线程队列时,互斥才会变慢。如果等待信号不使用
条件变量,那么可以得到taxye
在这种情况下,您可能必须等待调度内核勾号,以使
就绪
线程运行
,这可能非常长(30毫秒)

原子会让你获得最佳状态,甚至可能比条件变量更容易维护,这要归功于不必关心
虚假的
事件和
notify_one
notify_all

如果您检查C++11 maked STL的shared_ptr基类,则它们包含的
base_count
或(base_shared_count或其他内容)与您的需要完全相同。
如果愿意,您还可以检查新的boost::shared_count实现。

原子。如果您使用的是GCC,请搜索
\u sync内置项,否则我不知道。您需要一个正在进行的有意义的计数,还是只需要在所有线程结束后的最终计数?需要它在Linux和Windows上都工作。但如果需要,我会使用该代码。Boost::atomic是跨平台的!+1因为提到了C++11
,没有提到问题被标记为C++11:D+1,很好的概念:这对于更复杂的数据可能很方便。它就像一个简单的映射和约简。@DarkDust打败了我说这只是映射约简。你陷入了一个经典陷阱:你没有在每个变量之间填充数组ast的大小相当于缓存线(128字节)。因此,您没有注意到它,但硬件访问是由MESI协议联锁的。@v.oddou这就是我们采用第二种方法的原因。但这是一个非常好的主意!
#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";
    }
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;
}