Linux-----进程

一、什么是进程

程序是指编译好的二进制文件进程运行着的程序

区别在于:(1)程序占用磁盘,不占用系统资源,(2)进程占用内存,占用系统资源,(3)一个程序对应多个进程,一个进程对应一个程序,(4)程序没有生命周期,进程有生命周期

多道程序设计:出现多个进程一起执行的现象,这是因为每个进程都运行很短的时间,不断地重复这个过程,导致我们看起来多个进程是同时运行的。
在这里插入图片描述
进程的状态:
在这里插入图片描述

MMU的作用:(1)负责虚拟地址和物理地址的映射,(2)对内存访问级别进行修改

PCB:进程控制模块

注意:下图中,两个用户空间总即使存在相同的虚拟地址,也会映射到不同的物理地址中。
在这里插入图片描述

二、创建进程

1. 创建子进程

加入头文件:<unistd.h>
fork()有三个返回值,对应当前处于不同的状态:

pid_t pid = fork();
if(pid < 0)  {   //c创建失败 }
else if (pid == 0)  { //当前处于子进程中 }
else {  //当前处于父进程中 }
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(){
        
    printf("Begin...\n");
    pid_t pid = fork();  //create a subprocess

    if(pid < 0 ){
	printf("Create error!\n");
	exit(0);
    }	
    else if(pid == 0){
	//there is in subprocess:在子进程中
	//getpd()是获取当前进程id,getppid()是获取父进程id
	printf("I am a subprocess, pid = %d,ppid = %d\n",getpid(),getppid());
    }
    else{
	//there is in father process:在父进程中
    	printf("I am the father, subprocess_id = %d,pid = %d, ppid = %d\n",pid,getpid(),getppid());
    }

    printf("End...\n");

    return 0;
}

在这里插入图片描述
**观察结果:(1)子进程的id是3385,是对的,但子进程中显示父进程id是1,但实际上父进程显示自己的id是3384。 这是因为父进程先执行完了,子进程成为了一个僵尸进程 。 (2)还有就是同时输出了两个end… , 这是因为按照程序执行的规律,执行完了if中的语句,还会一直执行下面的公有部分,直到程序结束 **

更改代码:让父进程持续一段时间 sleep(1);

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(){
        
    printf("Begin...\n");
    pid_t pid = fork();  //create a subprocess

    if(pid < 0 ){
	printf("Create error!\n");
	exit(0);
    }	
    else if(pid == 0){
	//there is in subprocess
	printf("I am a subprocess, pid = %d,ppid = %d\n",getpid(),getppid());
    }
    else{
	//there is in father process
    	printf("I am the father, subprocess_id = %d,pid = %d, ppid = %d\n",pid,getpid(),getppid());
		sleep(1);     //让父进程持续一段时间
    }

    printf("End...\n");

    return 0;
}

更改代码:让子进程和父进程一直运行
在终端通过命令查看:ps aux
在这里插入图片描述
在终端通过命令查看ps ajx
在这里插入图片描述
从上图可以看到子进程显示的父进程id是对的

通过命令杀死父进程:发送9号信号:kill -9 3846
或者:kill 3846

看到子进程的父进程id变成了1,证明我们先前的猜想是对的。
在这里插入图片描述

出现的问题:下面这段代码应该输出一个being,两个end

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(){

    printf("begin...");
    fork();
    printf("end...\n"); 

    return 0;
}

但实际上输出如下图所示,原因是:linux下只有当出现换行符 \n 时才会将缓冲区输出,由于begin后没有 \n ,所以begin一直在缓冲区中。,直到遇到end 中的 \n 才将缓冲区输出
在这里插入图片描述

2.创建n个子进程

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(){

   int i;
   pid_t pid = -1;
   for(i=0;i<5;i++ ){
       pid = fork();
       if(pid == 0){
	  printf("I am child %d,pid=%d,ppid=%d\n",i,getpid(),getppid());
       }
       else if(pid > 0){
	  printf("I ma the father, pid=%d,ppid=%d\n",getpid(),getppid());
       }
   }   
   while(1){
       sleep(1);
   }

   return 0;
}

得到的结果如下所示:一共有32个进程,这是因为创建出的子进程也在创建它的子进程,但我们期望得到的不是这种结果。
在这里插入图片描述
代码修改:我们只需要创建一个子进程,然后执行子进程的操作,然后通过break将它退出循环,这样子进程就不会执行循环创建它的子进程的问题。
在这里插入图片描述
通过命令查看:ps aux | grep second
在这里插入图片描述

3.控制子进程和父进程退出的顺序

通过对 i 的判断进行分别

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(){

   int i;
   pid_t pid = -1;
   for(i=0;i<5;i++ ){
       pid = fork();
       if(pid == 0){
	  printf("I am child %d,pid=%d,ppid=%d\n",i,getpid(),getppid());
	  break;  //change point
       }
       else if(pid > 0){
	  //printf("I ma the father, pid=%d,ppid=%d\n",getpid(),getppid());
       }
   }   
   
   sleep(i);  //control the sequences of subprocesses and process

   //different process from i
   if(i < 5)  //subprocess: child
   {
	printf("I am childe %d, exit! pid=%d,ppid=%d\n",i,getpid(),getppid());
   }
   else{
	printf("I am father,exit! pid=%d,ppid=%d\n",getpid(),getppid());
   }

   return 0;
}

在这里插入图片描述

4.父子进程共享的内容

父子进程共享:
(1)文件描述符 – open、pipe
(2)内存映射区 – mmap函数

读取时共享同一块物理内存,在写入时将原数据复制到一块新的物理内存再进行改写。 即 读时共享、写时复制
在这里插入图片描述
父子进程并不共享全局变量的数据(符合读时共享,写时复制)。

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

int var = 100;

int main(){

    pid_t pid = fork();
    if(pid ==0){
	printf("child,var=%d,pid=%d,ppid=%d\n",var,getpid(),getppid());
	var = 1;
	printf("child,var=%d,pid=%d,ppid=%d\n",var,getpid(),getppid());
	sleep(5);
	printf("child,var=%d,pid=%d,ppid=%d\n",var,getpid(),getppid());
    }
    else if(pid>0){
	sleep(2);  //ensure the var change previously
	printf("father,var=%d,pid=%d,ppid=%d\n",var,getpid(),getppid());
	var = 2;
	printf("father,var=%d,pid=%d,ppid=%d\n",var,getpid(),getppid());
    }

    return 0;
}

如下图所示,父子进程的修改互不影响。
在这里插入图片描述

5.exec系列函数

6.孤儿进程和僵尸进程

1.定义
孤儿进程:父进程死了,子进程被init进程接管
僵尸进程:子进程死了,父进程没有回收子进程的资源(指PCB管理的资源)(为什么不让操作系统回收? 为了让你知道儿子是怎么死的)

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

int main(){

    pid_t pid = fork();
    if(pid ==0){
	sleep(2);
	printf("child will die,pid=%d,ppid=%d\n",getpid(),getppid());
    }
    else if(pid>0){
	while(1){
	     sleep(1);  
	     printf("father happy,pid=%d,ppid=%d\n",getpid(),getppid());
	}
    }

    return 0;
}

在这里插入图片描述
从上图看到子进程已经死了,但从下图看到子进程仍然占用了进程号,这就是僵尸进程。
在这里插入图片描述
如何杀掉僵尸进程?
(1)通过命令:kill -9 9791
如下图并没有解决问题,这是在鞭尸(子进程已经死了,再杀一次也没有用)

在这里插入图片描述
(2)解决方法:杀掉它的父进程:kill -9 9790,杀死父进程之后子进程由init接管和回收
在这里插入图片描述

7.回收子进程:wait(int* status)

pid_t wpid = wait(int* status);

返回值是回收的子进程pid,传入值是被杀死的原因

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

int main(){

    pid_t pid = fork();
    if(pid ==0){
	sleep(2);
	printf("child will die,pid=%d,ppid=%d\n",getpid(),getppid());
    }
    else if(pid>0){
	printf("father happy,pid=%d,ppid=%d\n",getpid(),getppid());
	pid_t wpid = wait(NULL);
	printf("wpid=%d\n",wpid);
	while(1){
	     sleep(1);  
	     printf("father happy,pid=%d,ppid=%d\n",getpid(),getppid());
	}
    }

    return 0;
}

在这里插入图片描述
回收之后没有显示僵尸进程。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值