gpt4 book ai didi

c++ - 在 C++ 中创建 Promises vector 并收集 future vector 的正确方法是什么?

转载 作者:行者123 更新时间:2023-12-02 09:51:42 25 4
gpt4 key购买 nike

我正在尝试将一个循环分配到多个线程中,使用 C++ Promise 和 Futures 在主线程中评估和收集聚合结果,如下所示:

std::vector<std::promise<std::tuple<uint64_t, uint64_t, uint64_t>>> promiseVector;
std::vector<std::future<std::tuple<uint64_t, uint64_t, uint64_t>>> futureVector;;
std::vector<std::thread *> threadPool;

// create threads
for(int ti = 0, initialval = 0; ti<max_num_threads; ti++, initialval += size_per_thread) {
// create promise
promiseVector.push_back(new std::promise<std::tuple<uint64_t, uint64_t, uint64_t>>(std::make_tuple(0, 0, 0)));

// create futures
futureVector.push_back(promiseVector[ti].get_future());

// create thread and start
threadPool.push_back(
new std::thread([&]{
uint64_t rv1 = 0, rv2 = 0, rv3 = 0;

// some threadwise work
for (int ri = initialval, i = 0; i < size_per_thread; ri += 8, i++) {
...
...
...
// update
rv1 = ...
rv2 = ...
rv3 = ...
}

promiseVector[ti].set_value(std::make_tuple(local_true_positive, local_false_positive, local_false_negative));
})
);
}

// accumulate results from all threads
for(int ti = 0; ti<max_num_threads; ti++) {
std::tuple<uint64_t, uint64_t, uint64_t> fval = futureVector[ti].get();
global_val1 += std::get<0>(fval);
global_val2 += std::get<1>(fval);
global_val3 += std::get<2>(fval);
}

// join all threads
for(int ti = 0; ti<max_num_threads; ti++) {
threadPool[ti]->join();
}
但它无法编译并出现以下错误:
 error: no matching constructor for initialization of 'std::promise<std::tuple<uint64_t, uint64_t, uint64_t> >' (aka 'promise<tuple<unsigned long, unsigned long, unsigned long> >')
promiseVector.push_back(new std::promise<std::tuple<uint64_t, uint64_t, uint64_t>>(std::make_tuple(0, 0, 0)));
^ ~~~~~~~~~~~~~~~~~~~~~~~~
我是 cpp 多线程的新手,在此先感谢。

最佳答案

不要使用 C++ new作为 Java/C# new . C++ 对所有类型都有工作值语义,你应该默认使用它。另一方面,new仅当您需要手动控制对象的生命周期并且在这种情况下更喜欢智能指针时才应使用。
C++ 有 using为复杂类型赋予新名称和 auto 的关键字自动推断它们。
这就是我编写此类代码的方式:

#include <vector>
#include <thread>
#include <future>
#include <tuple>

using result_t = std::tuple<uint64_t, uint64_t, uint64_t>;
std::vector<std::future<result_t>> futureResults;
//Store values directly
std::vector<std::thread> threadPool;

int main()
{
// create threads
constexpr int max_num_threads = 8;
constexpr int size_per_thread = 1;

int global_val1=0,global_val2=0,global_val3=0;

// Move around, if you need to capture something.
auto worker_fnc = [](std::promise<result_t> promise){
uint64_t rv1 = 0, rv2 = 0, rv3 = 0;
//Work
promise.set_value(std::make_tuple(0,0,0));
};

for(int ti = 0, initialval = 0; ti<max_num_threads; ti++, initialval += size_per_thread) {
// No need for pointers. Promise cannot be initialized.
std::promise<result_t> promise;

futureResults.push_back(promise.get_future());

// Create the thread, pass it its promise.
threadPool.push_back(std::thread(worker_fnc,std::move(promise)));
}

// accumulate results from all threads
for(int ti = 0; ti<max_num_threads; ti++) {
auto fval = futureResults[ti].get();
global_val1 += std::get<0>(fval);
global_val2 += std::get<1>(fval);
global_val3 += std::get<2>(fval);
}

// join all threads
for(int ti = 0; ti<max_num_threads; ti++) {
threadPool[ti].join();
}
}
几点注意事项/建议:
  • Promise 不能被初始化,这与你想要使用它们的方式相反,它们是尚不存在的结果的占位符。 这就是编译器所提示的。
  • 花时间了解move语义,可以入手here .它在您和我的代码中都大量使用,如果您尝试将一些表达式存储到变量中,代码的行为会有所不同/无法编译。
  • 总体而言,了解 C++ 何时以及如何复制和移动值对于编写正确的代码至关重要,尤其是在多线程中。 Java/C# 引用语义必须通过使用任何类型的指针或引用来显式请求。
  • 了解原因 promisestd::future 时必须显式移动变量, std::thread默认情况下会移动表达式。不能复制所有类型。
  • 没有必要在全局范围内持有 Promise - 只有编写者才能访问 Promise,只有读者才能知道 future 。
  • [&]构造是危险的,尤其是在线程的上下文中,因为它们很可能比任何局部变量都更长寿。例如。捕获本地promise变量而不是传递值会导致未定义的行为。另一个问题是捕获循环变量。明确指定捕获的引用,考虑复制小类型。您甚至可以使用 [&new_name_ref=old_name,new_name_copy=old_name2] 重命名变量。 .
  • 查看 std::async ,它为您处理线程、 promise 和 future 。对启动简单任务很有用,当你需要线程池时就没那么有用了。
  • 关于c++ - 在 C++ 中创建 Promises vector 并收集 future vector 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64062091/

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