Linux下中断程序导致写文件失败的分析

“Linux中的kill命令用来终止指定的进程（terminate a process）的运行，是Linux下进程管理的常用命令。通常，终止一个前台进程可以使用Ctrl+C键，但是，对于一个后台进程就须用kill命令来终止，我们就需要先使用ps/pidof/pstree/top等工具获取进程PID，然后使用kill命令来杀掉该进程。kill命令是通过向进程发送指定的信号来结束相应进程的。在默认情况下，采用编号为15的TERM信号。TERM信号将终止所有不能捕获该信号的进程。对于那些可以捕获该TERM信号的进程就要用编号为9的kill信号，强行“杀掉”该进程。”

“

1、kill命令可以带信号号码选项，也可以不带。如果没有信号号码，kill命令就会发出终止信号(15)，这个信号可以被进程捕获，使得进程在退出之前可以清理并释放资源。也可以用kill向进程发送特定的信号。例如：

kill -2 123

2、kill可以带有进程ID号作为参数。当用kill向这些进程发送信号时，必须是这些进程的主人。如果试图撤销一个没有权限撤销的进程或撤销一个不存在的进程，就会得到一个错误信息。

3、可以向多个进程发信号或终止它们。

4、当kill成功地发送了信号后，shell会在屏幕上显示出进程的终止信息。有时这个信息不会马上显示，只有当按下Enter键使shell的命令提示符再次出现时，才会显示出来。

5、应注意，信号使进程强行终止，这常会带来一些副作用，如数据丢失或者终端无法恢复到正常状态。发送信号时必须小心，只有在万不得已时，才用kill信号(9)，因为进程不能首先捕获它。要撤销所有的后台作业，可以输入kill 0。因为有些在后台运行的命令会启动多个进程，跟踪并找到所有要杀掉的进程的PID是件很麻烦的事。这时，使用kill 0来终止所有由当前shell启动的进程，是个有效的方法。

6、只有第9种信号(SIGKILL)才可以无条件终止进程，其他信号进程都有权利忽略。 下面是常用的信号：

HUP    1    终端断线

INT     2    中断（同 Ctrl + C）

QUIT    3    退出（同 Ctrl + \）

TERM   15    终止

KILL    9    强制终止

CONT   18    继续（与STOP相反， fg/bg命令）

STOP    19    暂停（同 Ctrl + Z）

$cmd & spid=$!

kill -s SIGINT $spid 是无法杀死进程的。进程仍旧在后台运行。若改成kill -9$spid。便可杀死进程。

“SIGINT can be caught and handled. It's like telling the process "Please stop what you're doing." The process is free to ignore the signal, or implement a handler that does anything it wants. The default behavior is to terminate, and this is what most processes will do. It's typical, but not required, for a process to handle SIGINT by gracefully terminating -- closing any open files, network connections, or database handles and stopping the current operation in such a way that prevents data loss or corruption.

SIGKILL can't be handled by the receiving process. If a process gets sent SIGKILL, it's toast, period. If a process receives SIGKILL in the middle of a database transaction or file write (for instance), it has no chance to exit gracefully and data loss or corruption may occur.

When you do Ctrl-C in the terminal, the terminal sends SIGINT to the running process. Like I said before, most processes will gracefully terminate on receiving SIGINT. Once it's terminated, it's just as surely ended as if it had been SIGKILL'ed or exited normally -- you shouldn't expect to see it in ps because it's still gone.

But there are some programs that don't respond to SIGINT in that way. bash is one example; if you hit Ctrl-C at a shell prompt, it'll just cancel whatever you've typed on that line -- not terminate the whole shell. Again, this is because the behavior when a process receives SIGINT is determined by the process itself. vi is another program that doesn't handle SIGINT by terminating.”

stackoverflow上面有一个问答正好解决了我的疑问。

Q:

I've read in a man page that when exit() is called all streams are flushed and closed automatically. At first I was skeptical as to how this was done and whether it is truly reliable but seeing as I can't find out any more I'm going to accept that it just works — we'll see if anything blows up. Anyway, if this stream closing behavior is present in exit() is such behavior also present in the default handler for SIGINT (the interrupt signal usually triggered with Ctrl+C)? Or, would it be necessary to do something like this:

#include <signal.h>
#include <stdlib.h>

void onInterrupt(int dummy) { exit(0); }

int main() {
signal(SIGINT, onInterrupt);
FILE *file = fopen("file", "a");
for (;;) { fprintf(file, "bleh"); } }

to get file to be closed properly? Or can the signal(SIG... and void onInterrupt(... lines be safely omitted?

Please restrict any replies to C, C99, and POSIX as I'm not using GNU libc. Thanks.

A:

1.So in C99, if it's closed then it's flushed.

2.You'll have to handle the signal if you want your buffers flushed. Otherwise the process will be terminated and the file descriptors closed without flushing the stdio buffers.

By default, a SIGINT will terminate the process abnornally. Processes so terminated do not call exit() and so do not have buffers flushed.

“fflush库函数的作用是把文件流里的所有未写出数据立刻写出。例如，你可以用这个函数来确保在试图读入一个用户响应之前，先向终端送出一个交互提示符。使用这个函数还可以确保在程序继续执行之前重要的数据都已经被写到磁盘上。有时在调试程序时，还可以用它来确定程序是正在写数据而不是被挂起了。注意，调用fclose函数隐含执行了一次flush操作，所以不必在fclose之前调用fflush。

fclose库函数关闭指定的文件流stream，使所有尚未写出的数据都写出。因为stdio库会对数据进行缓冲，所以使用fclose是很重要的。如果程序需要确保数据已经全部写出，就应该调用fclose函数。虽然当程序正常结束时，会自动对所有还打开的文件流调用fclose函数，但这样做就没有机会检查由fclose报告的错误了。与文件描述符一样，可用文件流的数目也是有限制的。这个限制由头文件stdio.h中的FOPEN_MAX常量定义，最小为8。

“所谓flush一个缓冲，是指对写缓冲而言，将缓冲内的数据全部写入实际的文件，并将缓冲清空，这样可以保证文件处于最新的状态。之所以需要flush，是因为写缓冲使得文件处于一种不同步的状态，逻辑上一些数据已经写入了文件，但实际上这些数据仍然在缓冲中，如果此时程序意外地退出（发生异常或断电等），那么缓冲里的数据将没有机会写入文件。flush可以在一定程度上避免这样的情况发生。”

posted @ 2015-04-18 21:21  IT屁民  阅读(2756)  评论(0编辑  收藏  举报