如何告诉 C++ 并发运行时重用前一个线程来继续任务

Posted

技术标签:

【中文标题】如何告诉 C++ 并发运行时重用前一个线程来继续任务【英文标题】:how to tell the c++ concurrency runtime to reuse the previous thread for task continuations 【发布时间】:2015-05-21 15:55:06 【问题描述】:

我使用 Visual c++ 并发运行时创建了一个任务,然后在其上安排了四个延续

#include <iostream>
#include <thread>
#include <ppltasks.h>

int main()

    concurrency::create_task([]
    
        std::cout << std::this_thread::get_id() << std::endl;
    )
    .then([]
    
        std::cout << std::this_thread::get_id() << std::endl;
    )
    .then([]
    
        std::cout << std::this_thread::get_id() << std::endl;
    )
    .then([]
    
        std::cout << std::this_thread::get_id() << std::endl;
    )
    .then([]
    
        std::cout << std::this_thread::get_id() << std::endl;
    );

    std::cin.get();

这将打印以下输出

29432
29432
25096
25668
42488

请注意,这 4 个延续任务并未安排在与初始任务相同的线程上。有没有办法在与初始任务相同的线程上安排延续?我相信在 c# 中使用TaskContinuationOptions.ExecuteSynchronously 选项是可能的。

【问题讨论】:

并发运行时之类的很多事情的重点是避免处理诸如明确决定哪些任务在哪些线程上运行之类的细节。您应该指定面向结果的约束(如排序要求)并让运行时处理细节。 @JerryCoffin 虽然我大体上同意你的观点,但我可以看到人们想要这样做的原因;取决于平台,线程创建可能有任意开销。无法强制运行时将后续任务安排到同一线程,这使得它无法用于某些用例。 @JonasWielicki:您是否考虑过在任务之间使用虚拟变量?这可能会导致运行时使用单个线程来避免在线程之间传递对象。 【参考方案1】:

通常,您可以使用task_continuation_context 控制继续执行的上下文,如the MSDN documentation describes。但是,相同的文档还提到:

仅在 Windows 应用商店应用程序中使用此类才有用。对于非 Windows 应用商店应用,任务延续的执行上下文由运行时决定,不可配置。

从您的代码 sn-p 看来,当您使用并发运行时时,您并没有从 Windows 应用商店应用程序中使用它。因此,上下文实际上总是任意的。

还有一个问题是您为什么要在与第一个任务相同的线程上显式运行后续任务:那么为什么不将这些任务的代码放在第一个任务中呢?延续的意义在于回到特定线程,以便继续在后台任务中完成的工作 - 这意味着,第一个任务必然是您希望执行的后台工作,而延续正在从主启动线程对这项工作做出反应。如果您希望留在后台线程上,请留在那里,不要费心继续进行这项工作。 (但是,如上所述,由于这不是 Windows 应用商店应用程序,所有这些延续和任务都在任意上下文中运行;运行时只会选择一个方便的可用线程。)

【讨论】:

以上是关于如何告诉 C++ 并发运行时重用前一个线程来继续任务的主要内容,如果未能解决你的问题,请参考以下文章

顺序并在一个线程中运行时差c ++ [关闭]

VS2010 的并发运行时和 unbounded_buffer<shared_ptr<T>>,有啥陷阱吗?

Semaphore-信号灯机制

[OS] 线程相关知识点

如何不等待 OpenMP 中的其他线程?

如何编写在 C++ openmp 上重用线程的代码?