从 std::thread 获取返回码? [复制]

Posted

技术标签:

【中文标题】从 std::thread 获取返回码? [复制]【英文标题】:Get return code from std::thread? [duplicate] 【发布时间】:2012-09-07 14:23:16 【问题描述】:

可能重复:C++: Simple return value from std::thread?

有没有办法从 std::thread 获取返回码?我有一个返回整数的函数,我希望能够在线程执行完毕后从函数中获取返回码。

【问题讨论】:

【参考方案1】:

不,这不是std::thread 的用途。

改为使用async 来获取future

#include <future>

int myfun(double, char, bool);

auto f = std::async(myfun, arg1, arg2, arg3);  // f is a std::future<int>

// ...

int res = f.get();

你可以使用f的成员函数wait_for(零超时)来查看结果是否就绪。

【讨论】:

我发现至少在 VC11 中,std::async 直到应用程序结束才会释放线程的所有资源,从而可能导致内存泄漏误报(如果您正在监视它们)使用例如 Visual Leak Detector)。所以也许使用 std::packaged_task 和 std::thread 提供一个类似的例子会更好。也不保证异步在单独的线程中运行。 @Klaim:我不太懂packaged_task,也不知道它的成语。请务必将其发布为答案;这对每个人都有好处。 是的,我会使用 wait_for 和零超时来检查是否准备就绪。 @AnthonyWilliams:哦,我没有意识到,你就是我刚买的书的那个人!这很令人兴奋。 @YagamyLight:它可能阻塞。当然,您不会创建async 未来并立即致电get。这个想法是您有其他事情要做,并且仅在您绝对需要结果时才阻止。【参考方案2】:

正如其他人所建议的,&lt;future&gt; 中的设施可用于此目的。但是我反对这个答案

不,std::thread 不能这样做

这是使用std::thread 做您想做的事情的一种方法。这绝不是唯一的方法:

#include <thread>
#include <iostream>

int func(int x)

    return x+1;


int main()

    int i;
    std::thread t([&] i = func(2););
    t.join();
    std::cout << i << '\n';

这将输出:

3

【讨论】:

是的,但你并没有真正从thread 对象中得到它;你得到它是因为你创建了一个使用引用来检索变量的仿函数。任何人都可以这样做;问题是关于从thread 对象中捕获返回值。 问题有两句话。我回答了第二个。 @HowardHinnant:你当然可以让线程操纵任何旧的共享状态(这可能是你应该这样做的方式)。但是你仍然没有“得到std::thread 的返回值......相反,你有一种穷人版本的packaged_task 我想。但这肯定是一个非常有用的观察。(通过顺便说一句,第二句话不是问题;-)。)【参考方案3】:

Kerrek SB 的回答是正确的,但我建议添加另一个示例(他建议应该是一个答案,所以在这里)。

我最近发现,至少在 VC11 中,std::async will not release all the resources of the thread until the end of the application,使得内存泄漏误报成为可能(如果您正在使用例如 Visual Leak Detector 监视它们)。

我的意思是,在大多数基本应用程序中,不值得查看此答案的其余部分,但是如果您像我一样需要检查内存泄漏并且不能承受误报,比如在 main 函数结束时没有释放的静态数据。如果是您的情况,那么这可能会有所帮助。

std::async默认不保证在单独的线程中运行,只有当你使用std::launch::async作为第一个参数时。否则由实现决定做什么,这就是为什么 VC11 实现将使用新的 Microsoft 并发运行时任务管理器将提供的功能作为推送到任务池中的任务来管理,这意味着以透明的方式维护和管理线程。有一些方法可以显式终止任务管理器,但这太特定于平台,当您想要 1) 确保启动一个线程并且 2) 稍后获得结果以及 3) 确保线程是时,这使得 async 成为一个糟糕的选择得到结果时完全释放

完全做到这一点的替代方法是将std::packaged_taskstd::threadstd::future 结合使用。它的完成方式与使用std::async 几乎相似,只是更冗长一些(这意味着您可以根据需要在自定义模板函数中对其进行概括)。

#include <packaged_task>
#include <thread>

int myfun(double, char, bool);

std::packaged_task<int(double, char, bool)> task(myfun, arg1, arg2, arg3); 

auto f = task.get_future();  // f is a std::future<int> 

首先我们创建一个任务,基本上是一个包含函数和将与未来关联的std::promise 的对象。 std::packaged_task 的工作方式大多类似于 std::function 的增强版:

现在我们需要显式地执行线程:

std::thread thread(std::move(task));

thread.detach();

移动是必要的,因为std::packaged_task 不可复制。仅当您只想使用未来进行同步时才需要分离线程 - 否则您将需要显式加入线程。如果你不这样做,当线程的析构函数被调用时,它只会调用std::terminate()

// ...

int res = f.get(); // Synchronization and retrieval.

【讨论】:

As I just read 如果函数查询结果,std::async 可能不会异步运行,即如果它实际上只是等待线程返回,并且在这种情况下等待单独的线程确实没有理由。【参考方案4】:

这是一个使用packaged_task的例子:

#include <future>
#include <iostream>

void task_waiter(std::future<int>&& f) 
    std::future<int> ft = std::move(f);
    int result = ft.get();
    std::cout << result << '\n';


int the_task() 
    return 17;


int main() 
    std::packaged_task<int()> task(the_task);
    std::thread thr(task_waiter, task.get_future());
    task();
    thr.join();
    return 0;

【讨论】:

主线程如何访问结果? @KerrekSB - 反过来做:从packaged_task 对象获取future 对象,然后将packaged_task 对象传递给运行任务的新线程。

以上是关于从 std::thread 获取返回码? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++ std::thread::hardware_concurrency() 获取CPU核心数

c++ std::thread 与静态成员挂起

std::thread 通过引用传递调用复制构造函数

std::thread 按引用传递调用复制构造函数

从具有本地 std::thread 对象的函数中退出而没有加入

带有类参数的 std::thread 初始化导致类对象被多次复制