14

何かが発生した回数をカウントする次のコードがあるとします。

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) できればミューテックスを使用しない最速の方法は何ですか? ありがとう。

更新: アトミックを使用するコメントを使用して、Intel Compiler バージョン 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";
    }
4

4 に答える 4

16

アトミック型を調べるとよいでしょう。ロック/ミューテックスを必要とせずにアクセスできます。

于 2014-02-17T17:10:08.373 に答える
3

array[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;
}
于 2014-02-17T17:22:04.670 に答える