分段故障和RAII
Segmentation Fault and RAII
这更像是一个哲学类型的问题。
在C++中,我们有一个很好的闪亮成语-RAII。但我经常认为它是不完整的。这与我的应用程序可以用SIGSEGV杀死这一事实并不一致。
我知道,我知道,像这样的程序是错误的你说。但有一个可悲的事实是,在POSIX(特别是Linux)上,您可以分配超出物理内存限制的内存,并在执行过程中满足SIGSEGV,使用正确分配的内存。
您可能会说:"应用程序死了,为什么要关心那些糟糕的析构函数没有被调用呢?"。不幸的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体。
我现在已经厌倦了设计技巧,破坏好的应用程序设计来应对这种情况。所以,我所要求的是为这类问题找到一个好的、优雅的解决方案。
编辑:
看来我错了,Linux上的应用程序被内核寻呼机杀死了。在这种情况下,问题仍然相同,但申请死亡的原因不同。
代码片段:
struct UnlinkGuard
{
UnlinkGuard(const std::string path_to_file)
: _path_to_file(path_to_file)
{ }
~UnlinkGuard() {
unlink();
}
bool unlink() {
if (_path_to_file.empty())
return true;
if (::unlink(_path_to_file.c_str())) {
/// Probably some logging.
return false;
}
disengage();
return true;
}
void disengage() {
_path_to_file.clear();
}
private:
std::string _path_to_file;
};
void foo()
{
/// Pick path to temp file.
std::string path_to_temp_file = "...";
/// Create file.
/// ...
/// Set up unlink guard.
UnlinkGuard unlink_guard(path_to_temp_file);
/// Call some potentially unsafe library function that can cause process to be killed either:
/// * by a SIGSEGV
/// * by out of memory
/// ...
/// Work done, file content is appropriate.
/// Rename tmp file.
/// ...
/// Disengage unlink guard.
unlink_guard.disengage();
}
一旦成功,我就用锉刀。失败时,我希望此文件丢失。
如果POSIX支持按文件描述符对以前未链接的文件进行link()
绑定,但没有这样的功能:(.
所以,我所要求的是为这类问题找到一个好的、优雅的解决方案。
无论是C++还是其他语言,都不存在。在这里,你面临的是一个基本的物理现实,而不是设计决策:当用户拔下插头时会发生什么?没有任何编程解决方案可以防止这种情况(好吧,重启后会恢复)。
所能做的是捕获POSIX信号,有时甚至可以处理它们——但这很古怪,而且有很多注意事项,另一个关于堆栈溢出的讨论对此进行了详细说明。
大多数资源不应该在segfault之后被清除。如果您无论如何都想这样做,只需在全局数组中收集这些资源(或者更确切地说,用于清理的处理程序),捕获SIGSEGV,在处理程序中迭代清理例程数组(希望相关内存仍然完好无损),然后执行清理。
更具体地说,对于临时文件,在系统的一个临时文件夹中创建它们会有所帮助。可以理解的是,它们并不总是由各自的应用程序进行清理,而是由系统或用户定期执行清理。
通常,无论语言或操作系统如何,解决方案都是在启动程序时清理,而不是(仅)在终止程序时清理。如果您的程序可以创建临时文件并在关闭时进行清理,请在启动程序时也清理这些临时文件。
当您的应用程序失效时,大多数其他东西,如文件句柄、tcp连接等,都会被操作系统杀死。
- 具有瞬态资源的RAII类
- 分段故障(堆芯转储)矢量
- C++中的动态铸造故障
- 数组的指针从不分段故障
- vscode g++链路故障:体系结构x86_64的未定义符号
- 访问被拒绝后,c++中的故障保护代码
- Windows 10-使用gtkmm-3.0库和g++[包括再现]的分段故障
- 使用RAII在给定次数的迭代后重新分配资源
- 调试 CUDA MMU 故障
- Geeksforgeeks C 程序故障排除:IEE 754 表示法为十进制
- 在文件夹迭代上实现 RAII
- Arch Linux.AUR 包 mysql 不能用 makepkg 构建.错误:构建 () 中出现故障
- 正在处理故障(堆芯转储)
- 在 Boost::fiber 中引发的BOOST_ASSERT故障 Visual Studio "Debug" 构建
- 如何进行故障排除:未定义对"非虚拟 thunk to ..."的引用
- 在 RAII 构造中修改 RVO 值是否安全?
- C++函数过载会导致 SEG 故障
- 分段故障 运行C++代码时出现 SIGSEGV
- RAII 等效于 FIFO 发布订单
- 分段故障和RAII