指定launch :: async时std :: async不执行

时间:2014-01-09 14:50:52

标签: c++ multithreading c++11 asynchronous

也许我错过了C ++ 11中新std::async的正确用法,但是这句话(在cppreference.com上):

  

如果设置了异步标志(即policy& std :: launch :: async!= 0),则async在单独的执行线程上执行函数f,就像由std :: thread(f,args)生成一样...),除非函数f返回值或抛出异常,它存储在可通过std :: future访问的共享状态中,异步返回给调用者。

让我觉得我的主题应该立即从这句话开始:

std::async(std::launch::async, MyFunctionObject());

无需等待调用std::future::get()。这似乎不是这种情况(使用MSVC 13进行编译)。如果这不是由这个语句本身触发的,如果我不关心std::future对象的返回值,应如何触发它?

示例:

#include <thread>
#include <iostream>
#include <array>
#include <future>

static std::mutex write_mutex;

class Cpp11Threads {
public:
    // Function operator for Function-Object
    void operator()() {
        const int num_threads = 50;

        // Static std array
        std::array<std::thread*, num_threads> worker_threads;

        // Range based
        for (std::thread*& thread : worker_threads) {

            // Lambda expression
            thread = new std::thread(
                [] {
                    static int i = 0;
                    write_mutex.lock();
                    std::cout << "Hello, I am happy Std thread #" << i++ << std::endl;
                    write_mutex.unlock();
                });
        }

        for (std::thread*& thread : worker_threads) {
            thread->join();
            delete thread;

            // nullptr instead of NULL
            thread = nullptr;
        }
    }
};

int main() {
    std::async(std::launch::async, Cpp11Threads());
    return 0;
}

2 个答案:

答案 0 :(得分:9)

首先要知道的是,MSVC std::async 符合C ++ 11标准。

在C ++ 11标准下,std::async的{​​{1}}返回值会阻塞,直到std::future完成。

MSVC的实施没有。这使他们的std::async看起来更加友好,但在实践中它非常棘手。

但是,由于std::async的行为是根据std::async描述的,我们可以看一下当您启动std::thread并且无法清理它时会发生什么。结果std::thread被有效分离。退出std::thread后,C ++标准未指定此类main会发生什么情况,并将其留给您的特定实现。

基于一些快速研究,当MSVC Windows程序离开main时,线程终止。

简而言之,您的程序需要与您以某种方式启动的线程重新同步,以便他们可以完成任务,并阻止主程序退出std::thread。一种简单的方法是在main任务之前存储已退回的std::future,并在async退出之前存储wait

如果你有一个符合要求的C ++ 11编译器,你尝试的main将无法异步,因为它会在它返回的匿名async被破坏后立即阻止。

最后,请注意,启动的std::future等可能无法安排在创建后立即运行。它们如何以及何时运行是不可预测的。

C ++ 11并发原语只是原语。他们中的许多人都有古怪的行为,例如thread如果std::thread调用terminate而未被detachjoin编辑而被销毁,async如果您不存储future,则会阻止阻止。它们可以用于简单的任务,也可以用于编写更高级别的库,但它们不是用户友好的。

答案 1 :(得分:2)

我不熟悉C ++ 11,但AFAIK每个程序都有一个主线程,它是你的main()函数执行的线程。当该线程的执行完成时,程序将与其所有线程一起完成。如果您希望主线程等待其他线程,请使用类似

的内容
  

在pthread_join

在Linux环境中(如果您手动创建了线程),或者完全

  

的std ::未来::得到()

在这个具体案例中。

退出主程序会终止你的线程,在你的情况下可能会阻止你启动线程