Проблема
При создании планировщиков последняя копия или перемещение объекта функции является последним местом, на которое когда-либо ссылался объект функции (рабочий поток). Если бы вы использовали std :: function для хранения функций в планировщике, то любые типы std :: promises или std :: packaged_task или другие подобные перемещения не работают, так как они не могут быть скопированы std :: function.
Аналогичным образом, если вы используете std :: packaged_task в планировщике, это накладывает ненужные накладные расходы, так как для многих задач вообще не требуется std :: future, возвращаемое упакованной задачей.
Распространенным и не лучшим решением является использование std :: shared_ptr <<strong> std :: обещания > или std :: shared_ptr <<strong> std :: packaged_task >, который работает, но это накладывает много накладных расходов.
Решение
Make_owner, похожий на make_unique с одним ключевым отличием, копия хода ИЛИ просто передает управление уничтожением объекта. Он в основном идентичен std :: unique_ptr, за исключением того, что он копируемый (он в основном всегда перемещается, даже на копии). Grosss ....
Это означает, что перемещение std :: functions не требует копий std :: shared_ptr, которые требуют подсчета ссылок, а также означает, что при подсчете ссылок значительно меньше накладных расходов и т. Д. Один атомарный указатель на объект будет потребуется, и копия ИЛИ передаст управление. Основным отличием является то, что копия также передает управление, это может быть немного нет-нет с точки зрения строгих правил языка, но я не вижу другого способа обойти это.
Это решение плохое, потому что:
- Он игнорирует копирование.
- Отбрасывает const (в конструкторе копирования и в операторе =)
Grrr
Это не такое приятное решение, как хотелось бы, поэтому, если кто-нибудь знает другой способ избежать использования общего указателя или только использования packaged_tasks в планировщике, я бы хотел услышать его, потому что я в замешательстве ...
Я довольно недоволен этим решением .... Есть идеи?
Я могу повторно реализовать std :: function с симметрией перемещения, но это кажется огромной болью в заднице, и у нее есть свои собственные проблемы с временем жизни объекта (но они уже существуют при использовании std :: function с захватом ссылок).
Некоторые примеры проблемы:
EDIT
Обратите внимание, что в целевом приложении я не могу выполнить std :: thread a (std :: move (a)), поскольку потоки планировщика всегда работают, в большинстве случаев они переводятся в состояние сна, никогда не включаются и никогда не останавливаются. В пуле потоков установлено фиксированное количество потоков, я не могу создавать потоки для каждой задачи.
auto proms = std::make_unique<std::promise<int>>();
auto future = proms->get_future();
std::thread runner(std::move(std::function( [prom = std::move(proms)]() mutable noexcept
{
prom->set_value(80085);
})));
std::cout << future.get() << std::endl;
std::cin.get();
И пример с упакованной_такой
auto pack = std::packaged_task<int(void)>
( []
{
return 1;
});
auto future = pack.get_future();
std::thread runner(std::move(std::function( [pack = std::move(pack)]() mutable noexcept
{
pack();
})));
std::cout << future.get() << std::endl;
std::cin.get();
EDIT
Мне нужно сделать это из контекста планировщика, я не смогу перейти в поток.
Обратите внимание, что вышеприведенное минимально воспроизводимо, std :: async не подходит для моего приложения.