今天决定对程序产生的不完整的临时文件进行下优化,当然这些临时文件是非预期的,在程序中都进行了处理,但是在某些情况下确实是发生了。
现象分析
首先可以确认的是这些临时文件都是程序在退出时候未处理生成的。当然程序全部是正常退出的,并没有异常崩溃,但是退出的方法有多种,比如Ctrl+C按键,比如直接点击控制台的关闭按钮,但是程序却没有在退出的时候调用析构进行资源释放。
诚然很多资源在进程关闭后可以被操作系统回收(先不谈规范性),比如内存、线程等。但是并非所有的资源都是系统默认资源,比如我们的应用中,程序是实时的写MP4媒体文件,如果结尾处不进行文件更新,那么文件肯定是不可用的。不过我们很多的释放都在析构函数也实现了一份,很大程度上都可以保证得到运行。不过仔细观察日志,可以发现确实是程序在某些情况下退出的时候没有处理释放。
从Win32的机制讲,处理程序退出的方法就是SetConsoleCtrlHandler
,一般我们的处理逻辑大概如下
BOOL WINAPI ConsoleHandler(DWORD event) { |
基本上就是在获取事件后给进程发消息,通知进程退出,逻辑大概如下
int main(int argc, char* argv[]) { |
深入排查
上面的代码基本都是比较通用的代码,在程序退出的时候基本都是可以看到日志中打印的catch日志的,说明这个机制是没有问题的。然后继续在程序退出过程中添加日志,这个时候就可以发现在Ctrl+C等情况下,退出日志基本是完整的,不过在直接关闭控制台按钮等方式下,日志却只打印了部分就结束了。这说明直接关闭程序应该是来不及释放资源就结束了的。仔细阅读下MSDN文档 SetConsoleCtrlHandler ,并不能获取到特别有用的信息。
直接写一段测试代码测试验证下
int pid = 0; |
分别通过Ctrl+C、关闭按钮关闭,任务管理器中结束进程,仔细观察就可以发现,Ctrl+C方式基本可以保证程序正常结束。但是后面两种,在不操作的情况下,在几秒后会被系统Kill。看来有些信号是有时限的啊,但是如果没有WaitForSingleObject
的阻塞,除了Ctrl+C方式外,其他两种情况程序迅速就结束了。
从网上提供的资料得到以下结论:
CTRL_CLOSE_EVENT
超时时间为5秒CTRL_LOGOFF_EVENT
和CTRL_SHUTDOWN_EVENT
超时时间为20秒
注销关机没测试,不过CTRL_CLOSE_EVENT
确实是大概在5秒的样子。
优化程序
知道了原因,接下来就是修改了,直接根据上面的测试例子改改就行,不过由于关键的CTRL_CLOSE_EVENT
时间只有5秒,也就意味着尽量把特别重要的释放优先进行。并且一定要在信号函数内部阻塞,而且为了确保程序不会阻塞卡死在信号函数内(毕竟还有Ctrl+C等情况),根据上面的超时时间,20秒是个不错的选择,即
WaitForSingleObject(g_handle, 20000); |
修改完成之后测试,之前会产生临时文件的场景基本已经OK了,当然这其中某些情况下只有5秒,并不能保证100%的可靠,不过应该也只能做到这个地步了。
PS:看到关机事件的超时是20秒,想到好多人吐槽关机慢就禁不住呵呵一笑,想我大Linux的SIGKILL还真是简单暴力啊!