当前位置:   article > 正文

计算机系统学习笔记(三):系统调用fork()(一)_fork返回的pid

fork返回的pid

fork基本知识

  • 父进程通过调用 fork 函数创建一个新的运行的子程序。

  • fork 函数被调用一次,却会返回两次:一次是在调用父进程中,一次是在新创建的子进程中。

  • 1)在父进程中,fork返回子进程的PID, 2)在子进程中,fork返回0。 3)如果出现错误,fork返回一个负值

*waitpid(pid_t pid,int statusp,int options)

  • pid:  
    pid>0时只等待进程ID为pid的子进程结束
     pid=-1时等待其所有的子进程中的任何一个(只要一个)结束
  • options:
    options=0(默认情况)时,挂起父进程,等待其子进程结束。返回子进程编号。
    options=WNOHANG时,父进程不挂起。如果一个子进程都没有结束的话,返回0;否则返回子进程编号。

kill

杀死进程

代码分析

代码0

void fork0() 
{
   
    if (fork() == 0) {
   
	printf("Hello from child\n");
    }
    else {
   
	printf("Hello from parent\n");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
进程图:
在这里插入图片描述
这段代码较简单,fork() 函数创建的子进程执行与父进程相同的代码,并返回参数。

代码1

void fork1()
{
   
    int x = 1;
    pid_t pid = fork();

    if (pid == 0) {
   
	printf("Child has x = %d\n", ++x);
    } 
    else {
   
	printf("Parent has x = %d\n", --x);
    }
    printf("Bye from process %d with x = %d\n", getpid(), x);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

getpid()

查看进程的pid值

在这里插入图片描述
进程图:
在这里插入图片描述
这段代码使用了getpid()函数查看进程的pid值

代码2

void fork2()
{
   
    printf("L0\n");
    fork();
    printf("L1\n");    
    fork();
    printf("Bye\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
进程图:
在这里插入图片描述
这里输出的结果无固定的顺序,因为子进程与父进程的运行是并发的。

代码3

void fork3()
{
   
    printf("L0\n");
    fork();
    printf("L1\n");    
    fork();
    printf("L2\n");    
    fork();
    printf("Bye\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述
在这里插入图片描述
同上个代码相同,结果不确定,但也有一定的顺序,比如最先输出的一定是“L0”。

代码4

void fork4()
{
   
    printf("L0\n");
    if (fork() != 0) {
   
	printf("L1\n");    
	if (fork() != 0) {
   
	    printf("L2\n");
	}
    }
    printf("Bye\n");
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述
在这里插入图片描述
因为 if() 函数的原因,子进程只运行两次。
代码5

void fork5()
{
   
    printf("L0\n");
    if (fork() == 0) {
   
	printf("L1\n");    
	if (fork() == 0) {
   
	    printf("L2\n");
	}
    }
    printf("Bye\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述
在这里插入图片描述
代码6

void fork6()
{
   
    atexit(cleanup);
    fork();
    exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

atexit()

在进程结束调用exit时,调用atexit()括号中的注册函数,注册几次就调用几次。并且它的调用顺序和登记顺序是相反的。与压栈顺序有关。

在这里插入图片描述
在这里插入图片描述
代码7

void fork7()
{
   
    if (fork() == 0) {
   
	/* Child */
	printf("Terminating Child, PID = %d\n", getpid());
	exit(0);
    } else {
   
	printf("Running Parent, PID = %d\n", getpid());
	while (1)
	    ; /* Infinite loop */
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述
运行到这里就会发现,无论怎样都不会出现下一条命令,这是使用ctrl+z ,会出现如下运行结果
在这里插入图片描述
这时输入ps命令,会发现父进程陷入了死循环,结果如下图:
在这里插入图片描述
这时用kill命令杀死父进程,然后用ps命令查看,恢复正常。
(因为我不是在一个时间运行的代码,所以pid输出的值不同,使用kill杀死进程时,要注意后面要加的是你运行时输出的那个pid的值)

代码8

void fork8()
{
   
    if (fork() == 0) {
   
	/* Child */
	printf("Running Child, PID = %d\n",
	       getpid());
	while (1)
	    ; /* Infinite loop */
    } else {
   
	printf("Terminating Parent, PID = %d\n",
	       getpid());
	exit(0);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述
输入ps命令查看,会发现子进程陷入了死循环
在这里插入图片描述
这时用kill命令杀死子进程,然后用ps命令查看,恢复正常。
在这里插入图片描述
代码9

void fork9()
{
   
    int child_status;

    if (fork() == 0) {
   
	printf("HC: hello from child\n");
        exit(0);
    } else {
   
	printf("HP: hello from parent\n");
	wait(&child_status);
	printf("CT: child has terminated\n")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/210607
推荐阅读
相关标签
  

闽ICP备14008679号