八_进程控制2 - fork()详解,与行缓冲,全缓冲的联系

本文详细介绍了Linux系统调用getpid和getppid用于获取进程ID以及fork函数创建子进程的相关知识。通过示例程序展示了fork后父子进程的执行顺序、输出差异,并解释了如何通过fflush防止重复打印。
摘要由CSDN通过智能技术生成

学习自李慧琴老师


1 getpid()/getppid
2 fork()


getpid()/getppid

NAME
getpid, getppid - get process identification

SYNOPSIS
#include <sys/types.h>
#include <unistd.h>

   pid_t getpid(void);
   pid_t getppid(void);

DESCRIPTION
getpid() returns the process ID of the calling process. (This is often used by routines that generate unique temporary filenames.)

getppid() returns the process ID of the parent of the calling process.


fork()

NAME
fork - create a child process

SYNOPSIS
#include <unistd.h>

   pid_t fork(void);

DESCRIPTION
fork() creates a new process by duplicating the calling process. The new process is referred to as the child process. The calling process is referred to as the parent process.

通过复制当前进程创建一个新进程,即父子进程相同,执行到的位置也相同

RETURN VALUE
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.

说明:
fork()后 ,在父进程当中返回的是子进程的pid,而在子进程中返回值为0。此时代码变成两份,两份一样的代码,就连执行到位置都一样。

在这里插入图片描述

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{

	pid_t pid;

	printf("[%d]:Begin!\n",getpid());

	pid = fork();
	if(pid < 0)
	{
		fprintf(stderr,"getpid() failed!");
		exit(1);
	}

	//child
	if(pid == 0)
	{
		printf("[%d]:Chiled is working\n",getpid());
	}
	else//parrent
	{
		printf("[%d]:Parrent is working\n",getpid());
	}

	printf("[%d]:End!\n",getpid());
	exit(0);

}



mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
[13186]:Begin!
[13186]:Parrent is working
[13186]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ [13187]:Chiled is working
[13187]:End!
^C
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

注意:
注意 程序运行结果:

[13186]:Begin!
[13186]:Parrent is working
[13186]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ [13187]:Chiled is working
[13187]:End!


第一部分 : 打印 Begin
第二部分:执行父进程语句 后 end
第三部分:执行子进程语句 后 end

问题1
首先 需要注意的是 父子进程的执行顺序,父子进程的执行顺序 是由程序调度器决定的,并不是我们决定,也有可能是 先执行子进程内容,再执行父进程内容。

问题2
其次 关于打印 Begin ,为什么只打印了一次 ?

关于问题1:
如果一定要子进程先运行,那么可以在 父进程语句中 sleep()一下:

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{

	pid_t pid;

	printf("[%d]:Begin!\n",getpid());

	pid = fork();
	if(pid < 0)
	{
		fprintf(stderr,"getpid() failed!");
		exit(1);
	}

	//child
	if(pid == 0)
	{
		printf("[%d]:Chiled is working\n",getpid());
	}
	else//parrent
	{
		sleep(1);
		printf("[%d]:Parrent is working\n",getpid());
	}

	printf("[%d]:End!\n",getpid());
	exit(0);

}

mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
[13255]:Begin!
[13256]:Chiled is working
[13256]:End!
[13255]:Parrent is working
[13255]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

关于问题2:有换行符 并 打印到行缓冲 终端
如下:

printf("[%d]:Begin!\n",getpid());

如果标准输出是终端设备,则标准输出是行缓冲,否则是全缓冲

在终端上只打印了一次 Begin 的原因在于,终端是行缓冲模式,由于后面的换行符,已经将缓冲区中内容刷新到磁盘,缓冲区已经清空。故在父进程中 会打印 Begin ,而在子进程 复制而来的缓冲区中并没有 Begin 信息,早已经在父进程中刷新,故子进程中 不会再次打印 Begin

变化1: 标准输出是终端 行缓冲 将换行符去掉

printf("[%d]:Begin!",getpid()); 

结果:

mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
[14003]:Begin![14003]:Parrent is working
[14003]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ [14003]:Begin![14004]:Chiled is working
[14004]:End!

打印两次 Begin, 此时 父进程与子进程中会分别打印一次 Begin,同理, 终端是标准输出,换行符刷新,此时没有换行符,在exit 之前 父进程的 Begin 信息存储在 缓冲区中,并没有写进磁盘。同理 复制而来的子进程的缓冲区中也有 Begin信息。所以两个进程在exit的时候 会打印两次 Begin

变化2:重定向到 全缓冲模式的文件

mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > TEST_FILE 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat TEST_FILE 
[14084]:Begin![14084]:Parrent is working
[14084]:End!
[14084]:Begin![14085]:Chiled is working
[14085]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 

当将标准输出重定向到一个文件的时候,此时标准输出是全缓冲模式,即 不论有没有换行符,都不会刷新缓冲区,即都不会写入磁盘,也就是两个进程的缓冲区中分别都有 Begin信息,故会打印两次。

重点: fork()之前 fflush所有打开的流,避免子进程重复打印

所以 介于以上的原因,我们一般在 fork()之前 fflush()一次,刷新所有成功打开的流:

#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>

int main(void)
{

	pid_t pid;

	printf("[%d]:Begin!\n",getpid());
	
	fflush(NULL);

	pid = fork();
	if(pid < 0)
	{
		fprintf(stderr,"getpid() failed!");
		exit(1);
	}

	//child
	if(pid == 0)
	{
		printf("[%d]:Chiled is working\n",getpid());
	}
	else//parrent
	{
		//sleep(1);
		printf("[%d]:Parrent is working\n",getpid());
	}

	printf("[%d]:End!\n",getpid());
	exit(0);

}


mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c 

mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out 
[14169]:Begin!
[14169]:Parrent is working
[14169]:End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ [14170]:Chiled is working
[14170]:End!

mhr@ubuntu:~/Desktop/xitongbiancheng/test$ 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值