Linux主函数 && fork


一、printf函数输出问题

printf 函数并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。
1) 缓冲区满
2) 强制刷新缓冲区 fflush
3) 程序结束时

示例1:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 int main(int argc, char* argv[],char* envp[])
 {
 printf("hello");
 sleep(3);
 exit(0);
 }

该程序会在睡眠三秒之后再输出hello结束

示例2:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 int main(int argc, char* argv[],char* envp[])
 {
 printf("hello");
 fflush(stdout);
 sleep(3);
 exit(0);

该程序会在输出hello之后睡眠三秒后结束

二、主函数参数介绍

int main( int argc, char* argv[], char* envp[])
(1) argc 参数个数
(2) argv 参数内容
(3) envp 环境变量

示例:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>

 //参数个数 参数内容 环境变量
 int main(int argc, char* argv[],char* envp[])
 {
 int i = 0;
 printf("argc=%d\n",argc);

 for( ;i < argc; i++ )
 {
 printf("argv[%d]=%s\n",i,argv[i]);
 }

 for( i = 0; envp[i] != NULL; i++ )
 {
 printf("envp[%d]=%s\n",i,envp[i]);
 }
 exit(0);
 }

执行程序:
在这里插入图片描述

三、进程复制 fork

3.1 fork 方法

pid_t fork(void);
函数返回类型 pid_t 实质是 int 类型,Linux 内核 2.4.0 版本的定义是:
在这里插入图片描述
fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。
在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1。

示例:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>

 int main(int argc, char* argv[],char* envp[])
 {
 char * s = NULL;
 int n = 0;

 pid_t pid = fork();
 assert( pid != -1 );

 if ( pid == 0 )
 {
 s = "child";
 n = 4;
 }
 else
 {
 s = "parent";
 n = 7;
 }

 int i = 0;

 for(; i < n; i++ )
 {
 printf("pid=%d,n=%d,&n=%x,s=%s\n",getpid(),n,&n,s);//getpid();获取pid函数
 sleep(1);
 }

 exit(0);
 }

输出:

在这里插入图片描述

要注意的几个问题:
1) 父子进程并发运行的理解
2) 逻辑地址 物理地址
3) 写时拷贝技术

3.2 写时拷贝

fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。
写时拷贝特点
(1)当父子进程都没有对进程中的变量进行改变时,父子进程共用相同的物理存储地址
(2)当父子进程任意一个对进程中的变量进行改变时,开辟新的物理地址

3.3 fork练习

下列程序输出几个“A”?

示例一:

int main(int argc, char* argv[],char* envp[])
{
int i = 0;
for( ; i < 2; i++ )
{
fork();
printf("A\n");
}
exit(0);
}

输出结果:

A
A
A
A
A
A

代码解析:
在这里插入图片描述

示例二:

 int main(int argc, char* argv[],char* envp[])
 {
 int i = 0;
 for( ; i < 2; i++ )
 {
 fork();
 printf("A");
 }
 exit(0);
 }

输出结果:

AAAAAAAA

代码解析:
在这里插入图片描述

示例三:

int main()
{
fork() || fork();
printf("A\n");
exit(0);
}

输出结果:

A
A
A

代码解析:
在这里插入图片描述

3.4 僵死进程及处理方法

(1) 僵死进程概念:子进程先于父进程结束,父进程没有调用 wait 获取子进程退出码。
(2) 如何处理僵死进程:父进程通过调用 wait()完成。
(3) Init 进程收养孤儿进程

代码示例:
先给出一个能产生僵死进程的代码,代码同上面的一样,如下:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>

 int main(int argc, char* argv[],char* envp[])
 {
 char * s = NULL;
 int n = 0;

 pid_t pid = fork();
 assert( pid != -1 );

 if ( pid == 0 )
 {
 s = "child";
 n = 4;
 }
 else
 {
 s = "parent";
 n = 10;
 }

 int i = 0;

 for(; i < n; i++ )
 {
 printf("pid=%d,n=%d,&n=%x,s=%s\n",getpid(),n,&n,s);//getpid();获取pid函数
 sleep(1);
 }

 exit(0);
 }

运行结果:

在这里插入图片描述
从上图中可以看到,当子进程结束后,并没有消失,仍然可以在系统中观测到,但此时
子进程其实已经运行结束了,此时子进程的状态被称为僵死状态,系统把处于该类状态的进
程称为僵死进程。 如果父进程先结束,子进程最后是不会变为僵死进程的。

如下代码,处理了僵死进程,子进程结束后,会消失:

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <assert.h>
 #include <sys/wait.h>

 int main()
 {
 char * s = NULL;
 int n = 0;

 pid_t pid = fork();
 assert( pid != -1 );

 if ( pid == 0 )
 {
 n = 4;
 s = "child";
 }
 else
 {
 n = 10;
 s = "parent";

 int val = 0;
 int id = wait(&val);

 if ( WIFEXITED(val) )
{
 printf("id=%d,val=%d\n",id,WEXITSTATUS(val));
 }

 }

 int i = 0;
 for( ; i < n; i++ )
 {
 printf("pid=%d,s=%s\n",getpid(),s);
 sleep(1);
 }

 exit(3);
 }

运行结果:
在这里插入图片描述
从上图可以看到子进程结束后,彻底从系统中消失了,并没有变成僵死进程。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

__小柒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值