C++ 生成多个线程,每个线程返回多个值

C++ 生成多个线程,每个线程返回多个值,c++,multithreading,c++11,stdthread,C++,Multithreading,C++11,Stdthread,我正在尝试生成多个线程来执行给定的任务。此任务根据传入的内容而有所不同,并将返回多个值 我尝试了以下几点,但都没有成功: std::vector<std::tuple<std::thread, Task, Result1, Result2>> workers; for (auto const& task : tasks) { Result1 result1; Result2 result2; std::tuple<std::threa

我正在尝试生成多个线程来执行给定的任务。此任务根据传入的内容而有所不同,并将返回多个值

我尝试了以下几点,但都没有成功:

std::vector<std::tuple<std::thread, Task, Result1, Result2>> workers;
for (auto const& task : tasks) {
    Result1 result1;
    Result2 result2;
    std::tuple<std::thread, Task, Result1, Result2> worker = std::make_tuple(std::thread(&Slave::performTask, this, task, std::ref(result1), std::ref(result2)), task, result1, result2);
    workers.emplace_back(worker);
}
for (auto& w : workers) {
    std::get<0>(w).join();
    std::cout << "Task=" << std::get<1>(w) << " Result1=" << std::get<2>(w) << " Result2=" << std::get<3>(w) << std::endl; 
}
执行输出:

任务=A结果1=A1结果2=A2

任务=B结果1=B1结果2=B2

任务=C结果1=C1结果2=C2

线程不可复制构造,因此错误
'thread(constthread&)'是私有的

线程是可构造移动的,因此您可以使用
std::move
向后放置一个右值引用:

workers.emplace_back(std::move(worker));
虽然这将解决眼前的问题,但请注意,您有一个更大、更险恶的问题,即悬空引用

您正在向线程函数传递对临时变量的引用(然后创建一个元组,其中包含
Result1
Result2
的副本)


现在,您不必尝试使用
结果
变量创建元组,并将引用传递给线程元组成员。

底部循环中的
t
s应该是
w
s,对吗?另外,不要害怕使用结构或类。一个由4项组成的元组急需名称。请编辑您的问题,以包含您可能看到的任何错误消息。请尝试提供一个最小的、可编译的、可验证的示例,以及对预期行为和实际观察到的行为的描述。调用
workers.emplace_back(std::move(worker))
适用于MSVC 2015。你在用什么编译器?你说得很好。我相信我在编写一个可编译的代码示例时解决了其中一些问题。看看我添加到问题中的代码,我真的建议你接受OOD,并将你的工人封装到工人类中。这将使您的代码更容易推理。为了确保结果对象的生命周期比您的循环更长,您也不一定需要使其成为指针。创建工作人员将非常简单-
工作人员-完成。我仍在考虑您关于重构代码以改进封装的建议。我主要的犹豫是创建一个只在这种特定情况下使用的类,但也许这是正确的方法。@Snooze为什么不创建一个类呢?您正在将“完成工作”所需的所有内容封装到一个“worker”类中。明天我将尝试这种方法,看看结果如何。问题中的代码示例只是一个微不足道的示例,因为我无法共享原始代码。希望重构能消除我在AOSP上看到的编译器错误。谢谢你的反馈!
workers.emplace_back(std::move(worker));
Result1 result1;
Result2 result2;

std::tuple<std::thread, Task, Result1, Result2> worker = 
    std::make_tuple(
        std::thread(
            &Slave::performTask, 
            this, 
            task, 
            std::ref(result1),  <-- here you pass a reference to a local variable
            std::ref(result2)), <-- 
        task, 
        result1,   <-- here you copy construct the tuple member from a local var
        result2);  <--
struct Worker
{
    Worker(Task& task)
        : task(task)
        , _thread(&Worker::performTask, this)
    {
    }

    void performTask()
    {
        result1 = task.foo();
        result2 = task.bar();
    }

    void join()
    {
        _thread.join();
    }

    Task    task;
    Result1 result1;
    Result2 result2;

private:
    std::thread _thread;
};