c++ - 以符合 C++ 标准的方式实现 std::malloc
问题描述
在回答问题之前进行快速的思想实验。想象一下,有人正在实现 std::malloc(比如说,JEMalloc 或 TCMalloc 的人之一)。他们需要的最基本的东西之一是能够知道一旦执行进入 std::malloc 的实现,程序将不会回调 malloc。
例如,
void* malloc(...) {
auto lck = std::unique_lock{malloc_mutex};
// .. memory allocation business logic
}
现在,如果在锁和分配的业务逻辑之间有一个信号,如果信号处理程序回调到 std::malloc,我们就会死锁。它不是为可重入而设计的,C++ 标准要求向 std::signal 注册的信号处理程序不回调到 operator new (可能回调到 malloc,因此需要用户定义的信号如果要考虑跨语言的所有实现可移植,则处理程序不会回调到 malloc 中)。
§[support.signal]p3
在最新版本的标准中概述了这一要求
- 评估是信号安全的,除非它包括以下内容之一:
对任何标准库函数的调用,除了普通的无锁原子操作和明确标识为信号安全的函数。[注意:这隐含地排除了依赖于库提供的内存分配器的 new 和 delete 表达式的使用。——尾注]
但是,C++ 标准似乎没有说明如何为执行线程实现函数堆栈(请参阅此问题:C++ 线程堆栈地址范围),这意味着operator new
如果程序在 std::malloc 的实现中调用函数调度可能会调用使用分段堆栈编译。
std::malloc
在那种情况下怎么可能实现这样的功能呢?如果 C++ 标准确实没有提供这样的保证,那又是什么呢?我们怎么知道一个正则函数的实现经过了正则的栈分配过程(栈指针递增)?哪个标准(例如 ABI、编译器、POSIX)涵盖了这一点?
解决方案
该实现需要为其堆栈帧使用信号安全分配器。这是因为信号处理程序中的函数调用(对非库函数)是允许的。实现可以使用malloc
or operator new
,但前提是这些分配器本身是信号安全的。
推荐阅读
- scala - Akka 是否支持此状态更新 Actor 模式
- python - 使用 selenium 进行网页抓取但得到不同的文本
- typescript - VSCode 扩展:在文件资源管理器的右键菜单中添加自定义命令
- go - golang反射初始化满足接口的结构
- r - “terms.formula(公式,数据=数据)中的错误:'。' 在公式中,在老鼠的“with()”函数中没有“数据”参数”
- c# - 如何检查从数据库中检索到的当前日期时间是否在 c# 中已经过了午夜?
- python - 根据 Python 中 group_by 数据框中的先前值计算百分比
- python - Bot 无法识别消息在初始发送后约 5 秒后被删除(服务器消息删除)
- python - 如何在 Jupyter Notebook 中导入 Pyperclip?
- windows - 使用批处理文件确定网络共享映射到哪个驱动器号