2015-05-29 5 views
5

Я написал следующий код, чтобы проверить std::async() на функции, возвращающие void с GCC 4.8.2 на Ubuntu.Действительно ли std :: async вызывается для функций, возвращающих пустоту?

#include <future> 
#include <iostream> 

void functionTBC() 
{ 
    std::cerr << "Print here\n"; 
} 

int main(void) 
{ 
#ifdef USE_ASYNC 
    auto i = std::async(std::launch::async, functionTBC); 
#else 
    auto i = std::async(std::launch::deferred, functionTBC); 
#endif 
    //i.get(); 
    return 0; 
} 

Если i.get(); является раскомментировать, то сообщение "Print here" всегда существует; однако, если i.get(); закомментирован, "Print here" существует, если и только если USE_ASYNC определен (то есть, std::launch::async всегда приводит к распечатке сообщения, а std::launch::deferred никогда).

Это гарантированное поведение? Каков правильный способ обеспечения возврата асинхронного вызова void?

+4

Если вы запрашиваете отложенный запуск и никогда не вызываете .get в это будущее, ваша функция никогда не будет выполнена. Это не имеет ничего общего с функцией, возвращающей void или любой другой тип. – sbabbi

ответ

7

std::launch::deferred означает «не запускайте это до тех пор, пока я не .wait() или .get()».

Как вы никогда .get() или .wait() ed, он никогда не бежал.

void не имеет никакого отношения к этому.

Для std::launch::async, стандартные состояния, деструктор возвращаемого будущегокиевстар (~future) будет блокировать до тех пор, задача не будет завершена (т.е. имеет неявный .wait()). Это нарушает MSVC специально, потому что они не согласны с этим проектным решением, и они борются за изменение стандарта: на практике это означает, что вы не можете полагаться на какое-либо поведение вообще от std::launch::async, возвращенного future, если вы хотите в будущем ваш код.

Без неявного wait в ~future было бы неопределенным, если бы оно фактически вызывало функцию при выходе main. Это произошло бы или нет. Возможно, вы могли бы вызывать UB, имея все еще активные потоки в конце main.

Вы можете задаться вопросом, что именно используется deferred: вы можете использовать его для вычисления очереди для ленивой оценки.

+0

Если я просто удаляю возвращаемое значение 'std :: async()' (удаляем 'auto i =' в моем фрагменте), версия 'std :: launch :: отложенная 'все еще пропускается. Разве это не нарушает «' будущее »будет блокироваться до завершения задачи»? – timrau

+0

«Будущее будет блокироваться до завершения задачи» в этом случае не применяется, из-за std :: launch :: deferred. Предложите вам подобрать копию «Эффективного современного C++» Мейера, см. Пункт 38. – kfsone

+1

@timrau Примечание о блокировке '' future' будет применяться только тогда, когда вы 'std :: async (std :: launch :: async). вызов 'std :: async (std :: launch :: async' без сохранения возвращаемого значения приводит к его уничтожению в конце инструкции, поэтому основной поток блокируется, пока задача async не будет завершена * на этой самой строке *. Сохранение его в 'auto i =' приведет к тому, что блок будет находиться в конце области. Перемещение возвращенного 'будущего' в другое' будущее' отложит блок до тех пор, пока будущее, в котором хранится состояние, наконец-то не будет уничтожено. – Yakk