Является ли std :: future :: get () или std :: future :: wait () заменой std :: thread :: join ()? - PullRequest
1 голос
/ 05 ноября 2019

Поток присоединится как thread.join() после вызова future.get() / future.wait() будущего, полученного из него? Могу ли я присоединиться к потоку, используя только его будущее, без прямого доступа к этому потоку?

Ответы [ 3 ]

2 голосов
/ 05 ноября 2019

Является ли std::future::get() или std::future::wait() заменой для std::thread::join()?

Нет, это разные вещи.

std::future - это инструмент синхронизации. Это обертка вокруг значения , которое не доступно сразу, но будет доступно. Он используется для передачи данных из асинхронной операции (которая может выполняться в другом потоке). Под капотом находится семафор, на котором get() ожидает, если необходимо.

A std::thread, с другой стороны, представляет фактический поток выполнения. Он может выдавать несколько результатов и, следовательно, подавать несколько std::promise с в течение срока службы. Что и должно быть, потому что запуск и присоединение к потоку - это относительно тяжелая операция, гораздо более тяжелая, чем ожидание в будущем. Вот почему следует предпочесть повторное использование потоков, публикацию асинхронных операций в пуле потоков и ожидание их результатов (std::packaged_task - полезная абстракция для этого).

Поток не завершится сразу после std::future::get(), даже если установка обещания - это последнее, что он делает. Это не связанные события.

1 голос
/ 05 ноября 2019

При использовании future вы не уверены на 100%, что создан новый поток. Например, когда вы создаете future с использованием политики выполнения std::launch::deferred, выполнение очень последовательное.

Цитирование стандарта:

std::launch::deferred: задачавыполняется в вызывающем потоке при первом запросе его результата (ленивая оценка)


На практике, когда вы создаете future с политикой выполнения std::launch::async большую часть времени, новыйпоток запущен. Изучив сгенерированный код с помощью gcc 10, я ясно вижу, что thread::join называется:

std::__future_base::_Async_state_commonV2::_M_complete_async():
        pushq   %rbp
        movq    %rsp, %rbp
        //more assembly maddness
        call    std::__future_base::_Async_state_commonV2::_M_join()

, что, в свою очередь, приводит к вызову thread::join().

std::__future_base::_Async_state_commonV2::_M_join():
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $48, %rsp
        movq    %rdi, -40(%rbp)
        movq    -40(%rbp), %rcx
        addq    $32, %rcx
        movq    %rcx, -24(%rbp)
        movl    $std::thread::join(), %eax
        ...
1 голос
/ 05 ноября 2019

Как указано в комментарии, std::future не имеет ничего общего с std::thread. Поэтому вы используете std::thread::join, только если вы используете std::thread, и вы используете std::future::get / std::future::wait, если вы используете std::future.

Под колпаком std::future существует пул потоков, которыйпринимает работу и разумно ее распределяет.

...