[英]non-blocking call of std::async: how is this version dangerous?
Some time ago I was looking for a way to invoke std::async
without the need of storing std::future
, thus not blocking the execution at the end of the scope.前段时间,我正在寻找一种无需存储
std::future
即可调用std::async
的方法,因此不会在 scope 结束时阻塞执行。 I found this answer which uses a captured std::shared_ptr
for an std::future
, therefore allowing to make a nonblocking call to std::async
.我发现这个答案使用捕获的
std::shared_ptr
作为std::future
,因此允许对std::async
进行非阻塞调用。
Another way of deferring a destructor invocation is to prevent it from to be called at all.另一种延迟析构函数调用的方法是完全阻止它被调用。 This can be achieved with in-place construction with
operator new
.这可以通过使用
operator new
的就地构造来实现。
Consider this version that uses a static thread local storage for an in-place constructed std::future<void>
:考虑这个使用 static 线程本地存储的版本,用于就地构造的
std::future<void>
:
template <class F>
void call_async(F&& fun) {
thread_local uint8_t buf[sizeof(std::future<void>)] = {0};
auto fut = new(buf) std::future<void>();
*fut = std::async(std::launch::async, [fun]() {
fun();
});
}
This version will not produce any heap-allocation related overhead, but it seems very illegal, though I am not sure why in particular.这个版本不会产生任何与堆分配相关的开销,但它似乎非常非法,尽管我不确定具体原因。
I am aware that it is UB to use an object before it has been constructed, which is not the case.我知道在构建之前使用 object 是 UB,但事实并非如此。 I am not sure why not calling
delete
in this case would resolve in UB (for heap allocation it is not UB).我不确定为什么在这种情况下不调用
delete
会在 UB 中解决(对于堆分配,它不是 UB)。
Possible problems that I see:我看到的可能问题:
std::promise
I suppose)std::promise
) https://ideone.com/C44cfe https://ideone.com/C44cfe
UPDATE更新
Constructing an object in the static storage directly (as has mentioned IlCapitano in the comments) will block each time a move assignment is called (shared state will be destroyed blocking the thread which has removed last reference to it).在 static 存储中直接构造一个 object(如评论中提到的 IlCapitano)将在每次调用移动分配时阻塞(共享 state 将被删除的阻塞引用线程)。
Not calling a destructor will case a leak because of not released references to the shared state.不调用析构函数将导致泄漏,因为未发布对共享 state 的引用。
It's undefined behaviour to end the lifetime of a non-trivial object without calling it's destructor, which happens as soon as there is a second call_async
invocation.在不调用它的析构函数的情况下结束非平凡 object 的生命周期是未定义的行为,一旦有第二次
call_async
调用就会发生这种情况。
"heap-allocation related overhead" is a misnomer if the only alternative is undefined behaviour.如果唯一的选择是未定义的行为,则“与堆分配相关的开销”是用词不当。 The
future
returned by async
has to live somewhere . async
返回的future
必须存在于某个地方。
The updated code has defined behaviour: it waits for the previous invocation to be done before launching the next one.更新后的代码已经定义了行为:它在启动下一个调用之前等待上一个调用完成。
Calling std::async
and ignoring the result sounds like "fire and forget".调用
std::async
并忽略结果听起来像是“一劳永逸”。 The simplest way to do that is to not use std::async
, but to create a detached thread:最简单的方法是不使用
std::async
,而是创建一个分离的线程:
std::thread thr(func, data...);
thr.detach();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.