C++ 不同值的并行搜索?

C++ 不同值的并行搜索?,c++,c++11,concurrency,parallel-processing,mutex,C++,C++11,Concurrency,Parallel Processing,Mutex,考虑以下代码: // Preprocessor #include <iostream> #include <chrono> #include <thread> #include <algorithm> #include <mutex> #include <random> // Main function int main() { // A random vector of size 100 with 10 diff

考虑以下代码:

// Preprocessor
#include <iostream>
#include <chrono>
#include <thread>
#include <algorithm>
#include <mutex>
#include <random>

// Main function
int main()
{
    // A random vector of size 100 with 10 different random values
    std::vector<unsigned int> vector = make_random_vector(100, 10);
    // At the end, the result should be the 10 different random values
    std::vector<unsigned int> result;
    // Mutex to deals with concurrency
    std::mutex mutex;
    // Parallel search
    parallel_for_each(vector.begin(), vector.end(), 
    [=, &result, &mutex](const unsigned int& i){
       /* CRITICAL SECTION: BEGIN */
       // If the current element is not yet in the resulting vector, inserts it
       if (!std::binary_search(result.begin(), result.end(), i)) {
           mutex.lock();
           result.insert(std::lower_bound(result.begin(), result.end(), i), i);
           mutex.unlock();
       }
       /* CRITICAL SECTION: END */
    });
    // Unique values
    result.erase(std::unique(result.begin(), result.end()), result.end());
    // Display the result
    std::for_each(result.begin(), result.end(), 
    [](const unsigned int& i){
        std::cout<<i<<std::endl;
    });
    // Finalization
    return 0;
}
make_random_vector
生成元素的随机向量,其中包含不同的随机值

// Produces a random vector of nelements with nvalues different random values
std::vector<unsigned int> make_random_vector(const unsigned int nelements, const unsigned int nvalues)
{
    std::vector<unsigned int> vector(nelements);
    std::vector<unsigned int> values(nvalues);
    std::random_device device;
    std::mt19937 engine(device());
    std::uniform_int_distribution<unsigned int> distribution1;
    std::uniform_int_distribution<unsigned int> distribution2(0, nvalues-1);
    std::for_each(values.begin(), values.end(), [=, &distribution1, &engine](unsigned int& i){i = distribution1(engine);});
    std::for_each(vector.begin(), vector.end(), [=, &distribution2, &engine, &values](unsigned int& i){i = values[distribution2(engine)];});
    return vector;
}
//生成元素的随机向量,其中包含不同的随机值
std::vector make_random_vector(常量无符号整数元素,常量无符号整数值)
{
std::向量(元素);
std::向量值(nvalue);
std::随机_装置;
std::mt19937发动机(设备());
标准:均匀分布1;
标准:均匀分布2(0,n值-1);
std::for_each(values.begin()、values.end()、[=、&distribution1、&engine](无符号int&i){i=distribution1(engine);});
std::for_each(vector.begin()、vector.end()、[=、&distribution2、&engine、&values](无符号int&i){i=values[distribution2(engine)];};
返回向量;
}

您的代码有问题,因为您只保护
结果的并发写访问,而不保护读取访问

解决方案是将互斥锁移到
if
的外部,如下所示:

[=, &result, &mutex](const unsigned int& i){
    std::lock_guard<std::mutex> lck (mutex);

    // If the current element is not yet in the resulting vector, inserts it
    if (!std::binary_search(result.begin(), result.end(), i)) {
        result.insert(std::lower_bound(result.begin(), result.end(), i), i);
    }
}
[=,&result,&mutex](常量unsigned int&i){
std::锁定保护lck(互斥);
//如果当前元素尚不在结果向量中,则插入它
如果(!std::binary_search(result.begin(),result.end(),i)){
result.insert(标准::下限(result.begin(),result.end(),i),i);
}
}
但它将打破平行的目的,因为:/

另一种解决方案是处理不同的结果集,并在循环结束时加入结果


另一种解决方案可能是的变体,但需要在每次插入时复制
结果。

而不是使用
std::vector
使用
Concurrency::combinable result
。这允许线程本地复制结果,而不需要任何互斥

使用每个
parallel_后,使用
组合每个
,并将结果放入一个
std::set
,以获得唯一值或您认为合适的任何方式

编辑:以下方法不需要std::mutex

 #include <ppl.h>

 void print_unqiue_numbers()
 {
    using namespace Concurrency;
    std::vector<unsigned int> vector = make_random_vector(100, 10);
    // At the end, the result should be the 10 different random values
    combinable<std::vector<unsigned int>> result;
    // Parallel search
    parallel_for_each(vector.begin(), vector.end(), 
    [=, &result](const unsigned int& i){
       auto& local_result = result.local(); // thread local variable.
       if (!std::binary_search(local_result.begin(), local_result.end(), i)) {
           local_result.insert(std::lower_bound(local_result.begin(),
                                                local_result.end(), i), i);
       }
    });

     std::set<unsigned int> unique_values;
     result.combine_each([&](std::vector<unsigned int> const& values)
     {
        for(auto v : values)
        {
            unique_values.insert(v);
        }
     });

     std::cout << "print the unique values\n";
     for (auto v : unique_values)
     {
         std::cout << v << '\n';
     }
  }
#包括
无效打印编号()
{
使用名称空间并发;
std::vector vector=生成随机向量(100,10);
//最后,结果应该是10个不同的随机值
组合结果;
//并行搜索
每个(vector.begin()、vector.end()、的并行\u,
[=,&结果](常量无符号整数(&i){
auto&local_result=result.local();//线程局部变量。
if(!std::binary_search(local_result.begin(),local_result.end(),i)){
local_result.insert(标准::下限(local_result.begin(),
局部_result.end(),i),i);
}
});
设置唯一的_值;
结果.组合每个([&](标准::向量常量和值)
{
用于(自动v:值)
{
唯一_值。插入(v);
}
});

std::cout If
result.insert
导致向量的重新分配,而另一个线程正在对其执行
binary\u搜索
,坏事情将会发生。我觉得唯一的方法是让每个任务返回一个结果向量,然后合并每个线程的结果。如果向量比cach大得多e大小,则搜索将受到内存带宽限制,并行方法可能没有多大帮助。如果进程的CPU带宽有限,或者当每个核心的大多数操作都在本地缓存中进行时,并行方法将有所帮助(请注意,外部缓存在某些CPU上的核心之间共享)。
 #include <ppl.h>

 void print_unqiue_numbers()
 {
    using namespace Concurrency;
    std::vector<unsigned int> vector = make_random_vector(100, 10);
    // At the end, the result should be the 10 different random values
    combinable<std::vector<unsigned int>> result;
    // Parallel search
    parallel_for_each(vector.begin(), vector.end(), 
    [=, &result](const unsigned int& i){
       auto& local_result = result.local(); // thread local variable.
       if (!std::binary_search(local_result.begin(), local_result.end(), i)) {
           local_result.insert(std::lower_bound(local_result.begin(),
                                                local_result.end(), i), i);
       }
    });

     std::set<unsigned int> unique_values;
     result.combine_each([&](std::vector<unsigned int> const& values)
     {
        for(auto v : values)
        {
            unique_values.insert(v);
        }
     });

     std::cout << "print the unique values\n";
     for (auto v : unique_values)
     {
         std::cout << v << '\n';
     }
  }