2016-03-27 12 views
9

C++でforループやrangeベースのループなどのループを並列に計算する方法があるのだろうかと思います。あなたはそのようなことをどのように実装しますか? Scalaから私はmap、filter、foreach関数を知っていますが、これらの並列を実行することも可能でしょうか? C++でこれを達成する簡単な方法はありますか? 私のプライマリplattformはLinuxですが、クロスプラットフォームで動作するといいでしょう。C++での並列ループ

+0

スレッドを使用するとよいでしょう。 –

+0

スレッドを初期化するのは本当に高価ですか? – Exagon

+1

fork()呼び出しと比較して。スレッドは、独自のPC、レジスタ、およびスタックを持っていることを除いて、メインスレッドからリソースを共有しているので高価ではありません。 –

答えて

8

お使いのプラットフォームは何ですか? OpenMPを見ることができますが、C++の一部ではありません。しかし、コンパイラによって広くサポートされています。

範囲ベースのforループについては、たとえばUsing OpenMP with C++11 range-based for loops?を参照してください。

http://www.open-std.orgには、将来のC++に並列構造/アルゴリズムを組み込むためのいくつかの努力が示されていますが、現在の状態はわかりません。

ただ、いくつかの典型的なコードを追加するUPDATE:

​​

スレッドの数がOMP_NUM_THREADS環境変数を経由して、実行時に設定することができます。

+0

私はループで半分に分割することは可能ですか?スレッドでは残りの半分が残りの部分を処理しますか? 3と同じようにスレッドで? – Exagon

+0

何を反復していますか?ルーピングにインデックスを使用できますか? –

+0

@Exagonどのようにスレッドから作業を取っているかは、あなたによって異なります。あなたは、あなたが仕事を分けることができるループの条件を作ることができます。 –

3

これは、操作を並行して実行するために使用できるthreads具体的にはpthreadsライブラリ関数を使用して実行できます。

あなたはここではそれらについての詳細を読むことができます:​​

のstd ::スレッドでも使用することができます。以下は

http://www.cplusplus.com/reference/thread/thread/は私がに、配列を分割するために、各スレッドのスレッドIDを使用しているコードがあります二つの半分:あなたは-lpthreadフラグを使用する必要がコンパイル中

#include <iostream> 
#include <cstdlib> 
#include <pthread.h> 

using namespace std; 

#define NUM_THREADS 2 

int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

void *splitLoop(void *threadid) 
{ 
    long tid; 
    tid = (long)threadid; 
    //cout << "Hello World! Thread ID, " << tid << endl; 
    int start = (tid * 5); 
    int end = start + 5; 
    for(int i = start;i < end;i++){ 
     cout << arr[i] << " "; 
    } 
    cout << endl; 
    pthread_exit(NULL); 
} 

int main() 
{ 
    pthread_t threads[NUM_THREADS]; 
    int rc; 
    int i; 
    for(i=0; i < NUM_THREADS; i++){ 
     cout << "main() : creating thread, " << i << endl; 
     rc = pthread_create(&threads[i], NULL, 
          splitLoop, (void *)i); 
     if (rc){ 
     cout << "Error:unable to create thread," << rc << endl; 
     exit(-1); 
     } 
    } 
    pthread_exit(NULL); 
} 

も覚えておいてください。 Ideoneのソリューションへ

リンク:http://ideone.com/KcsW4P

+1

はい、これを実現するには、使用する関数で 'start index'と' end index'を指定し、使用する各スレッドごとにそれを修正することができます。 – uSeemSurprised

+1

'pthread_create'関数は、スレッドに使用させたい関数の名前を含む引数を横取りします。この関数の引数を変更して、目的の結果を得ることができます。 – uSeemSurprised

+3

なぜ 'std :: thread'を持っているときにpthreadを使いたいのですか? –

8

std::asyncは、C++実行時制御の並列性を喜んでお勧めします。 cppreference.comから

例:我々は今使用できるC++ 17に並列アルゴリズムで

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <numeric> 
#include <future> 

template <typename RAIter> 
int parallel_sum(RAIter beg, RAIter end) 
{ 
    auto len = end - beg; 
    if(len < 1000) 
     return std::accumulate(beg, end, 0); 

    RAIter mid = beg + len/2; 
    auto handle = std::async(std::launch::async, 
           parallel_sum<RAIter>, mid, end); 
    int sum = parallel_sum(beg, mid); 
    return sum + handle.get(); 
} 

int main() 
{ 
    std::vector<int> v(10000, 1); 
    std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n'; 
} 
+0

wowありがとう私はこれを使用すると思います – Exagon

+0

どのようにC + +どのように並列タスクと非同期を処理する任意のドキュメントですか? – Exagon

+1

'std :: async()'の最初のパラメータは、フレームワークに与える自由(主にフォアグラウンドスレッドの使用を許可するかどうか)を指定します。バックグラウンドで何ができるかは、コンパイラに特有ですが、ほとんどのコンパイラではおそらくボックスにN = CPUコア数のシングルトンスレッドプールがあります。ベスト・ユース・ドキュメンテーション私が最後に行ったのは、メイヤーの最後の本の並行性の章です。 – bobah

5

std::vector<std::string> foo; 
std::for_each(
    std::execution::par_unseq, 
    foo.begin(), 
    foo.end(), 
    [](auto&& item) 
    { 
     //do stuff with item 
    }); 

並列にループを計算します。最初のパラメータは、execution policy

+0

コンパイラは実際にこの権利を実際にサポートしていますか? – nitronoid

+0

インテル®C++コンパイラー、あなたが学生の場合は、無料で入手できます。 – Kaznov

1

を指定します。C++ 11では、forループをわずか数行のコードで並列化できます。 これは、小さな塊にforループ分割し、スレッドに各サブループを割り当てる:

/// Basically replacing: 
void sequential_for(){ 
    for(int i = 0; i < nb_elements; ++i) 
     computation(i); 
} 

/// By: 
void threaded_for(){ 
    parallel_for(nb_elements, [&](int start, int end){ 
     for(int i = start; i < end; ++i) 
      computation(i); 
    }); 
} 

やクラスをwithing:

struct My_obj { 

    /// Replacing: 
    void sequential_for(){ 
     for(int i = 0; i < nb_elements; ++i) 
      computation(i); 
    } 

    /// By: 
    void threaded_for(){ 
     parallel_for(nb_elements, [this](int s, int e){ this->process_chunk(s, e); }); 
    } 

    void process_chunk(int start, int end) 
    { 
     for(int i = start; i < end; ++i) 
      computation(i); 
    } 
}; 

これを行うには、あなただけでは、以下のコードを配置する必要がありますヘッダファイルを自由に使用できます。

#include <algorithm> 
#include <thread> 
#include <functional> 
#include <vector> 

/// @param[in] nb_elements : size of your for loop 
/// @param[in] functor(start, end) : 
/// your function processing a sub chunk of the for loop. 
/// "start" is the first index to process (included) until the index "end" 
/// (excluded) 
/// @code 
///  for(int i = start; i < end; ++i) 
///   computation(i); 
/// @endcode 
/// @param use_threads : enable/disable threads. 
/// 
/// 
static 
void parallel_for(unsigned nb_elements, 
        std::function<void (int start, int end)> functor, 
        bool use_threads = true) 
{ 
    // ------- 
    unsigned nb_threads_hint = std::thread::hardware_concurrency(); 
    unsigned nb_threads = nb_threads_hint == 0 ? 8 : (nb_threads_hint); 

    unsigned batch_size = nb_elements/nb_threads; 
    unsigned batch_remainder = nb_elements % nb_threads; 

    std::vector<std::thread> my_threads(nb_threads); 

    if(use_threads) 
    { 
     // Multithread execution 
     for(unsigned i = 0; i < nb_threads; ++i) 
     { 
      int start = i * batch_size; 
      my_threads[i] = std::thread(functor, start, start+batch_size); 
     } 
    } 
    else 
    { 
     // Single thread execution (for easy debugging) 
     for(unsigned i = 0; i < nb_threads; ++i){ 
      int start = i * batch_size; 
      functor(start, start+batch_size); 
     } 
    } 

    // Deform the elements left 
    int start = nb_threads * batch_size; 
    functor(start, start+batch_remainder); 

    // Wait for the other thread to finish their task 
    if(use_threads) 
     std::for_each(my_threads.begin(), my_threads.end(), std::mem_fn(&std::thread::join)); 
}