C++ 关于std::async与std::launch::async参数启动的线程的混淆

C++ 关于std::async与std::launch::async参数启动的线程的混淆,c++,multithreading,c++11,future,stdthread,C++,Multithreading,C++11,Future,Stdthread,我对std::async函数有点困惑 说明书上说: 异步操作“如同在新的执行线程中”执行(C++11§30.6.8/11) 那是什么意思 据我所知,代码 std::future fut=std::async(std::launch::async,pow2,num); 应该在新线程上启动函数pow2,并通过值将变量num传递给线程,然后在将来某个时候,当函数完成时,将结果放入fut(只要函数pow2具有类似double pow2(double);)的签名)。但是说明书上写着“好像”,这让我觉得整

我对
std::async
函数有点困惑

说明书上说:

异步操作“如同在新的执行线程中”执行(C++11§30.6.8/11)

那是什么意思

据我所知,代码

std::future fut=std::async(std::launch::async,pow2,num);
应该在新线程上启动函数
pow2
,并通过值将变量
num
传递给线程,然后在将来某个时候,当函数完成时,将结果放入
fut
(只要函数
pow2
具有类似
double pow2(double);
)的签名)。但是说明书上写着“好像”,这让我觉得整个事情有点模糊不清

问题是:

在这种情况下总是启动新线程吗?我希望如此。我的意思是,对于我来说,参数
std::launch::async
在某种程度上是有意义的,因为我明确表示我确实想要创建一个新线程

代码呢

std::future fut=std::async(std::launch::deferred,pow2,num);
应该通过将
pow2
函数调用延迟到我编写类似
var=fut.get()之类的代码的点,使延迟求值成为可能。在本例中,参数
std::launch::deferred
,应该意味着我要明确声明,我不想要新线程,我只想确保在需要函数返回值时调用该函数

我的假设正确吗?如果不正确,请解释

另外,我知道默认情况下,函数的调用方式如下:

std::future fut=std::async(std::launch::deferred | std::launch::async,pow2,num);

在本例中,我被告知是否启动新线程取决于实现。同样,这意味着什么?

使用
std::async
标题的一部分)函数模板来启动(可能的)异步任务。它返回一个
std::future
对象,该对象最终将保存
std::async
的参数函数的返回值

当需要该值时,我们在
std::future
实例上调用get();这将阻塞线程,直到将来准备就绪,然后返回值
std::launch::async
std::launch::deferred
可以指定为
std::async
的第一个参数,以指定任务的运行方式

  • std::launch::async
    表示函数调用必须在其自己的(新)线程上运行。(考虑用户@T.C.的评论)
  • std::launch::deferred
    表示函数调用将被延迟,直到将来调用
    wait()
    get()
    。在这种情况发生之前,未来的所有权可以转移到另一个线程
  • std::launch::async | std::launch::deferred
    表示实现可以选择。这是默认选项(当您自己没有指定一个选项时)。它可以决定同步运行
  • 在这种情况下总是启动新线程吗?

    1.,我们可以说总是启动一个新线程

    我的假设[关于标准::启动::延期]正确吗?

    2.,我们可以说您的假设是正确的

    这是什么意思?[与正在启动或未启动的新线程相关,取决于实现]

    3.开始,由于
    std::launch::async | std::launch::deferred
    是默认选项,这意味着模板函数
    std::async
    的实现将决定是否创建新线程。这是因为一些实现可能正在检查过度调度

    警告

    以下部分与你的问题无关,但我认为记住这一点很重要

    C++标准称如果<代码> STD::将来< /C>保留与异步函数调用对应的共享状态的最后引用,则STD::Engor的析构函数必须阻塞,直到异步运行函数的线程结束。因此,由

    std::async
    返回的
    std::future
    实例将在其析构函数中阻塞

    void operation()
    {
        auto func = [] { std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); };
        std::async( std::launch::async, func );
        std::async( std::launch::async, func );
        std::future<void> f{ std::async( std::launch::async, func ) };
    }
    
    void操作()
    {
    auto-func=[]{std::this_thread::sleep_for(std::chrono::seconds(2));};
    std::async(std::launch::async,func);
    std::async(std::launch::async,func);
    std::future f{std::async(std::launch::async,func)};
    }
    
    这种误导性的代码会让您认为std::async
    调用是异步的,实际上是同步的。由
    std::async
    返回的
    std::future
    实例是临时的,并且将被阻止,因为当
    std::async
    返回时,它们的析构函数被正确调用,因为它们没有分配给变量

    std::async
    的第一次调用将阻塞2秒,然后从对
    std::async
    的第二次调用开始再阻塞2秒。我们可能认为对
    std::async
    的最后一次调用不会阻塞,因为我们将其返回的
    std::future
    实例存储在一个变量中,但由于它是一个局部变量,在作用域结束时被销毁,它实际上会在函数作用域结束时阻塞额外的2秒钟,当局部变量f被破坏时

    换句话说,调用
    operation()
    函数将同步阻止调用它的任何线程大约6秒钟。在C++标准的未来版本中可能不存在这样的要求。 我过去编译的信息来源
    #include <future>
    #include <thread>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        cout << "main thread id " << this_thread::get_id() << endl;
    
        future<int> f1 = async(launch::async, [](){
            cout << "future run on thread " << this_thread::get_id() << endl;
            return 1;
        });
    
        f1.get(); 
    
        future<int> f2 = async(launch::async, [](){
            cout << "future run on thread " << this_thread::get_id() << endl;
            return 1;
        });
    
        f2.get();
    
        future<int> f3 = async(launch::async, [](){
            cout << "future run on thread " << this_thread::get_id() << endl;
            return 1;
        });
    
        f3.get();
    
        cin.ignore();
    
        return 0;
    }
    
    main thread id 4164
    future run on thread 4188
    future run on thread 4188
    future run on thread 4188