问题 创建调度程序时,功能对象的最后副本或移动是该功能对象(由工作线程)引用的最后位置。如果要使用std :: function将函数存储在调度程序中,则任何std :: promises或std :: packaged_task或其他类似的仅移动类型均无效,因为它们无法被std :: function复制。
类似地,如果要在调度程序中使用std :: packaged_task,则由于许多任务根本不需要打包任务返回的std :: future,因此会带来不必要的开销。
常见但不是很好的解决方案是使用std :: shared_ptr << strong> std :: promise >或std :: shared_ptr << strong> std :: packaged_task >可以,但是会带来很多开销。
解决方案 一个make_owner(类似于make_unique,具有一个关键区别),移动 OR 副本只是转移了销毁对象的控制权。它与std :: unique_ptr基本相同,不同之处在于它是可复制的(即使在复制时,它也总是会移动)。毛....
这意味着移动std :: functions不需要std :: shared_ptr的副本,该副本需要引用计数,并且这也意味着引用计数等方面的开销明显减少。指向该对象的单个原子指针将需要并且移动 OR 副本将转移控制权。主要区别在于副本也可以转移控制权,就严格的语言规则而言,这可能有点不行,但我看不出有其他解决办法。
此解决方案不好,原因是:
Grrr 这不是我想要的解决方案,因此,如果有人知道另一种避免使用共享指针或仅在调度程序中使用packaged_tasks的方法,我很想听听它,因为我很困惑……>
我对这种解决方案非常不满意。...有什么想法吗? 我能够通过移动符号来重新实现std :: function,但这似乎给屁股带来了极大的痛苦,并且它在对象生命周期方面也有其自身的问题(但是在将std :: function与引用捕获一起使用时它们已经存在)。 / p>
问题的一些示例:
编辑 请注意,在目标应用程序中,我无法执行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();
还有一个带有packaged_task的示例
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();
编辑
我需要从调度程序的上下文中执行此操作,我将无法移至线程。
请注意,以上内容是最低可复制的,std :: async不适合我的应用程序。
答案 0 :(得分:1)
主要问题是:为什么在传递给std::function
构造函数之前要用std::thread
包装一个lambda?
这样做非常好:
std::thread runner([prom = std::move(proms)]() mutable noexcept
{
prom->set_value(80085);
});
您可以找到有关为何std::function
不允许您存储只能移动的lambda here的解释。
如果您要将带有包装好的lambda的std::function
传递给某个函数,而不是:
void foo(std::function<void()> f)
{
std::thread runner(std::move(f));
/* ... */
}
foo(std::function<void()>([](){}));
您可以这样做:
void foo(std::thread runner)
{
/* ... */
}
foo(std::thread([](){}));
更新:这可以通过老式的方式完成。
std::thread runner([prom_deleter = proms.get_deleter(), prom = proms.release()]() mutable noexcept
{
prom->set_value(80085);
// if `proms` deleter is of a `default_deleter` type
// the next line can be simplified to `delete prom;`
prom_deleter(prom);
});