Можно ли выполнить код асинхронно на тред-пуле?
От: Basil2 Россия https://starostin.msk.ru
Дата: 12.07.19 20:43
Оценка:
Я по наивности полагал, что std::async(std::launch::async) сделает свое дело, но оказалось фигушки ((

std::thread{}.detach() не очень вариант, т.к. долгий и может провалиться.

А надо-то всего лишь выполнить кусочек кода, не ожидая его результата, но используя тред пул. Неужели блин в великом и могучем С++ нельзя это сделать?!

Вариант
static std::future<void> fut;
fut = std::async(DoTask);
компилируется и даже вроде работает, но что-то он мне так попахивает, блин.

Можно ли как-то это сделать не через жопу более корректно?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Re: Можно ли выполнить код асинхронно на тред-пуле?
От: reversecode google
Дата: 12.07.19 22:47
Оценка: 2 (1)
на текущий момент этого в стандарте нет
только планируют завозить executor в С++23

так что или асио/буст асио
или что то свое на коленке
можно еще нагуглить
https://stackoverflow.com/questions/40806894/is-there-an-implementation-of-stdasync-which-uses-thread-pool
Re[2]: Можно ли выполнить код асинхронно на тред-пуле?
От: so5team https://stiffstream.com
Дата: 13.07.19 07:11
Оценка: 1 (1)
Здравствуйте, reversecode, Вы писали:

R>или что то свое на коленке

R>можно еще нагуглить

Просто на правах рекламы наколеночный вариант на базе SObjectizer:
#include <so_5/all.hpp>

using namespace std::chrono_literals;

class async_pool_t final {
    class executor_t final : public so_5::agent_t {
    public:
        using task_t = std::function<void()>;

        executor_t(context_t ctx) : so_5::agent_t{std::move(ctx)} {
            so_subscribe_self().event(
                    [](const task_t & task) { task(); },
                    so_5::thread_safe);
        }
    };

    so_5::wrapped_env_t sobj_;
    const so_5::mbox_t exec_mbox_;

    static auto make_executor(
            so_5::environment_t & env,
            std::size_t pool_size) {
        return env.introduce_coop(
                so_5::disp::adv_thread_pool::make_dispatcher(env, pool_size).binder(),
                [](so_5::coop_t & coop) {
                    return coop.make_agent<executor_t>()->so_direct_mbox();
                });
    }

public:
    async_pool_t(std::size_t pool_size)
        : sobj_{}
        , exec_mbox_{make_executor(sobj_.environment(), pool_size)}
    {}

    void async(std::function<void()> task) {
        so_5::send<executor_t::task_t>(exec_mbox_, std::move(task));
    }
};

int main() {
    async_pool_t pool{4};

    pool.async([] {
            std::cout << "First task (250ms)" << std::endl;
            std::this_thread::sleep_for(250ms);
        });
    pool.async([] {
            std::cout << "Second task (150ms)" << std::endl;
            std::this_thread::sleep_for(150ms);
        });
    pool.async([] {
            std::cout << "Third task (50ms)" << std::endl;
            std::this_thread::sleep_for(50ms);
        });
    pool.async([] {
            std::cout << "Fourth task (350ms)" << std::endl;
            std::this_thread::sleep_for(350ms);
        });
    pool.async([] {
            std::cout << "Fifth task (150ms)" << std::endl;
            std::this_thread::sleep_for(150ms);
        });

    std::cout << "All tasks started" << std::endl;
}


Здесь создается пул рабочих нитей и один актор, который способен все свои заявки обрабатывать параллельно. Далее каждая новая задача отсылается этому актору в виде объекта std::function<void()>. Функция main() завершается только когда все отосланные актору заявки будут обработаны.

Если фантазировать дальше, то с учетом наличия в SObjectizer таймеров, можно, при необходимости, сделать так, чтобы задачи запускались спустя какое-то время. Либо, чтобы запускались до истечения какого-то времени (а потом просто игнорировались).
Re: Можно ли выполнить код асинхронно на тред-пуле?
От: a7d3  
Дата: 13.07.19 10:58
Оценка: 2 (1)
Здравствуйте, Basil2, Вы писали:

B>Вариант

B>
B>static std::future<void> fut;
B>fut = std::async(DoTask);
B>
компилируется и даже вроде работает, но что-то он мне так попахивает, блин.


B>Можно ли как-то это сделать не через жопу более корректно?


Это корректный подход, потому что:

If the std::future obtained from std::async is not moved from or bound to a reference, the destructor of the std::future will block at the end of the full expression until the asynchronous operation completes


Кому начхать на то, как будет выполняться, тот сделает std::thread{}.detach()
А остальные управляют ожиданием через время жизни std::future.
{
    SomeClass abc;
...
    auto res = std::async(DoTask);
...
    здесь будет ожидание окончания DoTask в деструкторе std::future
    и только потом уже вызов SomeClass::~SomeClass()
}

Если в ходе работы программы стало ясно, что нет надобности ждать окончания DoTask, то этот res можно подвергнуть тому самому «moved from or bound to a reference» — в соответствующей ветке условного оператора.
Re[3]: Можно ли выполнить код асинхронно на тред-пуле?
От: AeroSun  
Дата: 13.07.19 12:13
Оценка: -1
Это какой-то франкенштейн
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.