c++ - std::async 的非阻塞调用:这个版本有多危险?
问题描述
前段时间我正在寻找一种std::async
无需存储即可调用的方法std::future
,从而不会在作用域结束时阻塞执行。我发现这个答案使用捕获std::shared_ptr
的std::future
,因此允许对 进行非阻塞调用std::async
。
另一种延迟析构函数调用的方法是完全阻止它被调用。这可以通过就地施工来实现operator new
。
考虑这个版本,它使用静态线程本地存储进行就地构造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();
});
}
这个版本不会产生任何与堆分配相关的开销,但它似乎非常非法,尽管我不确定具体原因。
我知道在构造对象之前使用它是UB,事实并非如此。我不确定为什么delete
在这种情况下不调用会在 UB 中解决(对于堆分配,它不是 UB)。
我看到的可能问题:
- 多次在一个对象上调用构造函数
- 修改状态时的竞争条件(
std::promise
我想是内部的)
更新
直接在静态存储中构造一个对象(正如评论中提到的 IlCapitano)将在每次调用移动分配时阻塞(共享状态将被破坏,阻塞已删除对它的最后引用的线程)。
由于未释放对共享状态的引用,不调用析构函数将导致泄漏。
解决方案
在不调用它的析构函数的情况下结束非平凡对象的生命周期是未定义的行为,一旦有第二次call_async
调用就会发生这种情况。
如果唯一的选择是未定义的行为,则“与堆分配相关的开销”是用词不当。future
返回的人async
必须住在某个地方。
更新后的代码已经定义了行为:它在启动下一个调用之前等待上一个调用完成。
推荐阅读
- javascript - 设置 ag 网格独立图表最小 x 轴值不起作用
- javascript - WordPress InnerBlocks Gutenberg 不正确保存
- opencv - 使用带有烧瓶的网络摄像头
- r - 如何计算两个变量(Var1=boys,Var2=girls)中一个变量(Variable=boys)在行中进行 10 次左右观察的比例
- python - 为熊猫数据框中的行和列设置“元名称”
- swift - 将 PassthroughSubject<[Int], Never> 映射到 AnyPublisher
- javascript - PayPal支付成功后显示HTML按钮
- python-3.x - 如何在python中的数组中创建多个范围?
- python - 使用 pandas 对一列中的文本数据进行分类,并在下一列中说明相应的类别
- c# - C#打开文本文件,如双击