Во время обзора кода я наткнулся на фрагмент кода, который в основном сводится к следующему:
#include <iostream>
#include <future>
#include <thread>
int main( int, char ** )
{
std::atomic<int> x( 0 );
std::future<void> task;
for( std::size_t i = 0u; i < 5u; ++i )
{
task = std::async( std::launch::async, [&x, i](){
std::this_thread::sleep_for( std::chrono::seconds( 2u * ( 5u - i ) ) );
++x;
} );
}
task.get();
std::cout << x << std::endl;
return 0;
}
Я не был уверен,
- гарантируется, что все задания выполняются при распечатке результата,
- будут ли выполняться задачи один за другим (т.е. назначение задачи будет блокировать) или нет.
Я не мог ответить на этот вопрос из чтения документации в Интернете, поэтому я подумал, что напишу фрагмент выше, чтобы узнать, что на самом деле делает наш компилятор.
Теперь я узнал, что ответ на вопрос о том, что делает gcc-5, нерешительно, и это сделало меня еще более любопытным: можно было бы предположить, что назначение либо блокирует, либо не блокирует.
Если он блокируется, время, затрачиваемое программой, должно быть в основном суммой времени, которое отдельные задачи выполняют для выполнения. Первый занимает 10 секунд, второй 8, третий 6, четвертый 4 и последние 2 секунды. Таким образом, в общей сложности он должен принимать 10 + 8 + 6 + 4 + 2 = 30 секунд.
Если он не блокируется, он должен принимать до тех пор, пока последняя задача, т.е. 2 секунды.
Вот что происходит: требуется 18 секунд (измеряется с использованием времени. /a.out или старых добрых часов). Немного поработав с кодом, я обнаружил, что код ведет себя так, как будто назначение будет чередующимся образом блокировать и не блокировать.
Но это не может быть правдой, верно? std::async
возможно, возвращается к std::deferred
половине времени? Мой отладчик говорит, что он порождает два потока, блокирует до тех пор, пока оба потока не выйдут, а затем создаст еще два потока и т.д.
Что говорит стандарт? Что должно произойти? Что происходит внутри gcc-5?