这更像是一种哲学类型的问题。
在 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()
,则可以获得此功能,但是没有这样的功能:(。
答案 0 :(得分:5)
所以,我要问的是解决这类问题的优秀解决方案。
无,对于C ++和其他语言都不存在。你在这里遇到了一个基本的物理现实,而不是一个设计决定:当用户拔出插头时会发生什么?没有任何编程解决方案可以防范这种情况(好吧,重启时还原)。
你可以做的是抓住POSIX信号,有时你甚至可以处理它们 - 但它很有趣,并且有很多警告,another discussion on Stack Overflow details。
在段错误之后,不应该清除大多数资源。如果你想要这样做,只需在全局数组trap SIGSEGV中收集这些资源(或者更确切地说,清理处理程序),迭代处理程序中的清理例程数组(希望相关内存仍然完好无损) ),并执行清理。
更具体地说,对于临时文件,它有助于在系统的一个临时文件夹中创建它们。据了解,这些并不总是被各自的应用程序清理干净,系统或用户都会定期执行清理工作。
答案 1 :(得分:3)
通常,无论语言或操作系统如何,解决方案都是在启动程序时清理,而不是(仅)在终止时清理。如果您的程序可以创建在关机时清理的临时文件,那么在启动程序时也要清理临时文件。
当应用程序死亡时,操作系统会杀死大多数其他内容,如文件句柄,tcp连接等。