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 Ifresult.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';
}
}