gpt4 book ai didi

c++ - 用于构造 std::thread 时,仿函数和 lambda 之间有什么区别

转载 作者:太空宇宙 更新时间:2023-11-04 16:12:25 27 4
gpt4 key购买 nike

我正在测试 C++ Concurrency in Action 一书中的代码。基本上,它使用多线程来实现与 std::accumulate 相同的功能。如下所示,我尝试使用 lambda 代替仿函数,但我的代码给出了错误的结果。 可以切换变量 is_from_book 来测试这两种方式。

#include <thread>
#include <algorithm>
#include <vector>
#include <iostream>

namespace para {

template<typename Iter, typename Value>
struct AccumulateBlock
{
void operator ()(Iter first, Iter last, Value& result)
{
result = std::accumulate(first, last, result);
}
};

template<typename Iter, typename Value>
Value parallel_accumulate(Iter first, Iter last, Value init_val)
{
using std::size_t;
size_t length = std::distance(first, last);
if(length == 0) return init_val; // trivial case

size_t min_per_thread = 25;
size_t max_threads = (length + min_per_thread - 1) / min_per_thread;
size_t hardware_threads = std::thread::hardware_concurrency();
size_t num_threads = std::min((hardware_threads!=0 ? hardware_threads : 2), max_threads);
size_t block_size = length/num_threads;
std::vector<Value> results(num_threads);
std::vector<std::thread> threads{num_threads - 1};

Iter block_start = first;
for(unsigned long idx=0; idx!=(num_threads-1); ++idx )
{
Iter block_end = block_start;
std::advance(block_end, block_size);

if(bool is_from_book = false) //code from the book that uses functor
{
threads[idx] = std::thread{
para::AccumulateBlock<Iter, Value>{},
block_start,
block_end,
std::ref(results[idx])
};
}
else //my code that tries to use lambda instead of functor
{
threads[idx] = std::thread{
[&]{
results[idx] = std::accumulate(block_start, block_end, results[idx]);
}
};
}

block_start = block_end;
}

para::AccumulateBlock<Iter, Value>{}(block_start, last, results[num_threads-1]);

for(auto& t : threads) t.join();
return std::accumulate(results.begin(), results.end(), init_val);
}
}//namespace

int main()
{
std::vector<int> v(10000,1);
auto sum = para::parallel_accumulate(v.begin(), v.end(), 0);
std::cout << "sum = " << sum << std::endl;

return 0;
}

我的问题是什么问题?我做得对吗?这两种方式有什么区别吗?如何解决?谢谢。

最佳答案

您通过引用捕获所有内容,因此 idxblock_startblock_end 在线程脚下移动,导致各种未定义行为。

通过引用捕获结果——或者,更安全的是,只捕获线程需要的数组元素——其他的通过值:

Value & result = results[idx];
threads[idx] = std::thread{
[&result,block_start,block_end]{ // or [=,&result] if you like brevity
result = std::accumulate(block_start, block_end, result);
}
};

关于c++ - 用于构造 std::thread 时,仿函数和 lambda 之间有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26971625/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com