fork与exit、_exit的配合使用

#include "light.h"

int main(int argc, char *argv[])
{
    printf("Hello world\n");
    write(STDOUT_FILENO, "Ciao\n", 5);
    if (fork() == -1)
        errExit("fork");
    /* Both child and parent continue execution here */
    exit(EXIT_SUCCESS);
}

When we run this program with standard output directed to the terminal, we see the expected result:
$ ./fork_stdio_buf
Hello world
Ciao
However, when we redirect standard output to a file, we see the following:
$ ./fork_stdio_buf > a
$ cat a
Ciao
Hello world
Hello world

Why?
recall that the stdio buffers are maintained in a process's user-space memory.
Therefore, these buffers are duplicated in the child by fork(). When standard out-put is
directed to a terminal, it is line-buffered by default, with the result that the newline-terminated
string written by printf() appears immediately. However, when standard output is directed to a
file, it is block-buffered by default. Thus, in our example, the string written by  printf() is
still in the parent’s  stdio  buffer at the time of the fork(), and this string is duplicated in
the child. When the parent and the child later call  exit(), they both flush their copies of the stdio
buffers, resulting in duplicate output.

We can prevent this duplicated output from occurring in one of the following ways:
	As a specific solution to the stdio  buffering issue, we can use fflush() to flush the
stdio buffer prior to a  fork() call. Alternatively, we could use  setvbuf() or setbuf()
to disable buffering on the  stdio  stream.
	Instead of calling  exit(), the child can call  _exit(), so that it doesn’t flush stdio
buffers. This technique exemplifies a more general principle: in an application that creates
child processes, typically on ly one of the processes (most often the parent) should terminate
via exit(), while the other processes should terminate via _exit(). This ensures that only one
process calls exit handlers and flushes stdio buffers, which is usually desirable.

The output of the write() in the program doesn’t appear twice, because write() transfers data
directly to a kernel  buffer, and this buffer is not dupli-cated during a  fork(). By now, the reason
for the second strange aspect of the program’s output when redirected to a file should be clear.
The output of  write() appears before that from printf()  because the output of write() is immediately
transferred to the kernel buffer cache, while the output from printf() is transferred only when
the stdio  buffers are flushed by the call to exit().
时间: 2024-10-26 23:51:54

fork与exit、_exit的配合使用的相关文章

使用gdb查看exit和_exit调用

通篇假设未曾使用过gdb,一般的发行版都会携带这个工具,要是没有,只能自己找找,如何安装了. 本文并未详细说明exit(_exit)里边详细过程,只是表述如何进入. 测试代码如下: #include <stdio.h> #include <stdlib.h> void func() {      printf("atexit "); } int main(int argc, char* argv[]) {      atexit(func);      prin

exit与return区别

1. exit用于结束正在运行的整个程序,它将参数返回给OS,把控制权交给操作系统:而return 是退出当前函数,返回函数值,把控制权交给调用函数.2. exit是系统调用级别,它表示一个进程的结束:而return 是语言级别的,它表示调用堆栈的返回.3. 在main函数结束时,会隐式地调用exit函数,所以一般程序执行到main()结尾时,则结束主进程.exit将删除进程使用的内存空间,同时把错误信息返回给父进程.4. void exit(int status); 一般status为0,表示

Linux编程之调用fork()两次以避免僵死进程

当我们只fork()一次后,存在父进程和子进程.这时有两种方法来避免产生僵尸进程: 父进程调用waitpid()等函数来接收子进程退出状态. 父进程先结束,子进程则自动托管到Init进程(pid = 1). 目前先考虑子进程先于父进程结束的情况:     若父进程未处理子进程退出状态,在父进程退出前,子进程一直处于僵尸进程状态. 若父进程调用waitpid()(这里使用阻塞调用确保子进程先于父进程结束)来等待子进程结束,将会使父进程在调用waitpid()后进入睡眠状态,只有子进程结束父进程的w

FORK()子进程对父进程打开的文件描述符的处理

总的来说,子进程将复制父亲进程的数据段,BSS段,代码段,堆空间,栈空间和文件描述符.而对于文件技术符关联内核文件表项(即STRUCT FILE结构),则是采取了共享的方式. 下面代码说明. I值分离,但FD共享. 1 [root@localhost ~]# vim fork_descriptor.c 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <fc

linux实训

目  录 Unit 1 操作系统安装.... 3 1.1 多操作系统安装... 3 1.1.1 VMware简介... 3 1.1.2 VMWare基本使用... 4 1.2 安装Red Hat Linux 9.0. 15 1.3 思考题... 15 [实习报告]... 16 Unit 2  Linux命令接口使用.... 17 2.1 访问Linux系统... 17 2.1.1 创建用户组... 17 2.1.2 删除用户组... 17 2.1.3 创建用户... 18 2.1.4 删除用户.

python实现的守护进程用法实例

  本文实例讲述了python实现的守护进程(Daemon)用法.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 def createDaemon(): "'Funzione che crea un demone per eseguire un determinato programma-"' import os #

Python脚本后台运行的几种方式

 这篇文章主要介绍了Python脚本后台运行的几种方式,linux下后台运行.通过upstart方式实现.通过bash脚本实现.通过screen.tmux等方式实现,需要的朋友可以参考下     一个用python写的监控脚本test1.py,用while True方式一直运行,在ssh远程(使用putty终端)时通过以下命令启动脚本: 代码如下: python test1.py & 现在脚本正常运行,通过ps能看到进程号,此时直接关闭ssh终端(不是用exit命令,是直接通过putty的关闭按

Linux系统调用详解(实现机制分析)--linux内核剖析(六)

系统调用概述 计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制.也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call).在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口. 一般情况下应用程序通过应用编程接口API,而不是直接通过系统调用来编程.在Unix世界,最流行的API

子进程及时知道父进程已经退出的最简单方案

  [精彩] 子进程及时知道父进程已经退出的最简单方案? http://www.chinaunix.net 作者:yuonunix  发表于:2003-10-31 10:14:14 [发表评论] [查看原文] [C/C++讨论区][关闭] 要父进程知道子进程退出,这太容易了,但是要子进程知道父进程退出,可有点麻烦.       父进程如果退出,子进程如何知道呢,最笨的方法,父子进程之间建立socket连接,然后建立心跳,没隔1秒测试一把,当然太笨了,通过管道,可以吗?如何做?有更加简单的方法吗?