如何通过引用从线程返回结果?

时间:2018-03-10 07:43:11

标签: c++

可以通过引用 传递参与另一个线程中运行的函数的参数。

是否可以返回来自另一个线程中运行的函数的结果,引用。如果是这样,怎么样?

2 个答案:

答案 0 :(得分:3)

  

可以将参数传递给在另一个函数中运行的函数   线程,通过引用。

不直接,因为所有参数都被复制或移动到另一个线程中,但您可以模拟使用std::refstd::cref传递的引用。见std::thread constructor documentation

  

通过值移动或复制线程函数的参数。如果   一个引用参数需要传递给线程函数,它有   被包裹(例如std::refstd::cref)。

当然,在使用它完成另一个线程之前,你必须确保引用的对象没有被破坏。

这是一个小例子:

#include <iostream>
#include <thread>

void f(int& x)
{
    std::cout << x << '\n';
}

int main()
{
    int a = 1;
    std::thread t(f, std::ref(a));
    t.join();
    // safe, because `a` still exists at this point,
    // but the thread is already finished
}
  

是否可以从另一个函数中运行的函数返回结果   线程,通过引用。

没有

首先,这没有意义,因为如果调用者被阻塞等待被调用的函数返回,它将失败线程的目的(但是,见下文)。

其次,这不是线程的工作方式。正如C ++标准所述,§4.7/ 1 [intro.multithread]

  

当一个线程创建另一个线程时,初始调用顶层   新线程的功能由新线程执行,而不是由新线程执行   创建线程。

换句话说,每个线程都有“自己的堆栈”。这与在同一个线程中使用函数完全不同。您不能使用return将任何内容从新线程返回到原始线程。

您通过原始线程可访问的其他线程设置数据间接“返回”某些内容。如果您愿意,可以通过模拟参考来实现:

#include <iostream>
#include <thread>

void f(int& x, int& result)
{
    result = x * x;
}

int main()
{
    int a = 2;
    int result;
    std::thread t(f, std::ref(a), std::ref(result));
    t.join();
    std::cout << result << '\n';
}

除了这些玩具示例之外,共享数据更真实地是std::atomic或由std::mutex / std::scoped_lock等人保护。

话虽如此,你一定要看看std::future。期货不会改变线程在内部的工作方式,但它们提供了一个类似普通函数调用堆栈的抽象层。

答案 1 :(得分:-1)

是的,但要非常小心,因为每个线程可能使用相同的资源并导致“数据竞争”。你应该使用“互斥”或其他机制来进行系统化 例如:没有互斥锁

#include<iostream>
#include<string>
#include<vector>
#include<thread>

static std::vector<std::string> glm;
void addMap(std::vector<std::string> &glm, std::string name)
{
    glm.push_back(name);
    std::cout << "Add: " << name << "\n";
}

int main()
{
    std::thread t[4];
    std::vector < std::string> names = { "Hellen", "Peter", "Bob", "Zoe" };

    for(int i = 0; i < names.size(); i++)
    {
        t[i] = std::thread(addMap, glm, names[i]);
    }

    for(int i = 0; i < names.size(); i++)
    {
        t[i].join();
    }
}

如上所示,我们预计会打印出来: 添加:海伦 添加:彼得 添加:鲍勃 添加:Zoe

但事实并非如此。有时,它会打印不够的名称,有时订单会有所不同。 使用互斥锁的示例:

#include<iostream>
#include<string>
#include<vector>
#include<thread>
#include<mutex>
static std::vector<std::string> glm;
std::mutex mut;
void addMap(std::vector<std::string> &glm, std::string name)
{
    mut.lock();
    glm.push_back(name);
    std::cout << "Add: " << name << "\n";
    mut.unlock();
}


int main()
{
    std::thread t[4];
    std::vector < std::string> names = { "Hellen", "Peter", "Bob", "Zoe" };

    for(int i = 0; i < names.size(); i++)
    {
        t[i] = std::thread(addMap, glm, names[i]);
    }

    for(int i = 0; i < names.size(); i++)
    {
        t[i].join();
    }
}

使用多线程编码时要非常小心