Linux进程

1.进程概述

1.1 程序和进程

  • 程序
    • 磁盘文件, 只占用磁盘空间
  • 进程
    • 运行的应用程序,不占磁盘空间,占用内存和CPU
    • 每个进程都有一个虚拟地址空间

1.2 并行和并发

在这里插入图片描述并发:

  • 单位时间内处理任务总量,总量越大,并发量越大
    并行:
  • 处理任务的硬件资源有多个,多个处理器同时工作叫做并行

1.3 进程状态

在这里插入图片描述

进程有五种状态: 
初始态(创建态):   -> 从无到有

就绪态:
	- 进程有了, 但是进程并没有运行
	- 进程可以争抢cpu, 抢到了cpu就变成了运行态
	- 运行态的进程cpu时间片用完了, 强制失去cpu
	- 就绪的状态被杀死 -> 退出态
	
运行态:
	- 正常的进程, 并且有cpu资源, 这个时候程序被执行
	- 运行态的进程cpu时间片用完了 -> 就绪态
	- 运行过程中, 程序中某些函数前置进程失去cpu
		- sleep(100) -> 挂起(阻塞)态 -> 100s之后变成了就绪态
		- 阻塞函数 read() -> 条件不满足进程阻塞 -> 条件满足了 -> 就绪态
		
	- 运行的状态被杀死 -> 退出态

阻塞态:
	- 这是程序中某些函数造成的强制性的行为
		- sleep()
		- 阻塞函数
	- 可以直接被杀死 -> 退出态
	
退出态:
	释放资源

2. 进程创建

2.1 进程ID

2.1.1 命令

  • 查看进程
$ ps aux
   a: 查看所有终端信息
   u: 查看用户相关信息
   x: 显示和终端无关的进程信息
$ 查看某个进程信息
ps aux | grep bash
$ ps ajx
  • 杀死进程
# 发信号给某一进程
$ kill -9 进程PID
$ kill -l		# 查看linux中的信号

2.1.2 函数

  • 获取当前进程ID
pid_t getpid(void);
  • 获取当前父进程ID
pid_t getppid(void);

2.2 进程创建

  • 如何创建进程,父子进程区分
    #include <unistd.h>
    
    int main()
    {
    	pid_t pid = fork(void);
    	if(pid > 0)
    	{
    		//父进程
    	}
    	else if(pid == 0)
    	{
    		//子进程
    	}
    }
    
  • 循环创建多个进程(以3个为例)
    int main()
    {
    	for(int i=0;i<3;i++)
    	{
    		pid_t pid = fork()
    		if(pid == 0)
    		{
    			break;
    		}
    	}
    }
    

2.3 父子进程

子进程的地址空间的从父进程复制过来的, 但是不是 100% 一样

  • 区别
    • 内核区:
      - 进程ID不同
      - 进程状态
      - cpu寄存器状态
      - pcb 部分不同 (pcb进程控制块)
  • 共同点
    • 内核区:
      - 文件描述符表
    • 用户区:
      • 完全一样(只局限于创建出的瞬间)

3. execl和execlp函数

execlexeclp函数的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。

//exec族函数特点: 调用这个函数不会创建额外的进程的, 会将原来进程虚拟地址空间的代码段替换      
// 函数原型
#include <unistd.h>

int execl(const char *path, const char *arg, .../* (char  *) NULL */);
参数:
	- path: 要启动的可执行程序的路径, 一般使用绝对路径(建议)
    - arg: 随便写个名字(一般和执行的程序名相同), 用于 ps aux 最后看到的进程的名字
    - ...: 变参
        指定的是执行的可执行程序需要的参数, 参数写完之后加一个NULL(哨兵)
        以字符串的形式指定
返回值:
	成功: 没有返回值
    失败: -1
        
// 启动可执行程序一般在系统目录中 /bin  /usr/bin, 并被这些路径被配置到了环境变量PATH中
int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
参数:
	- file: 要启动的可执行程序的文件名, 因为程序执行的时候回去PATH环境变量中搜索对应的路径
    - arg: 随便写个名字(一般和执行的程序名相同), 用于 ps aux 最后看到的进程的名字
    - ...: 变参
        指定的是执行的可执行程序需要的参数, 参数写完之后加一个NULL(哨兵)
        以字符串的形式指定
返回值:
	成功: 没有返回值   失败: -1
    
// 举例:
execl("/home/robin/test", "test", "-npvl", NULL);
execlp("ls", "ls", "-lhaH", NULL);

4.进程控制

4.1 结束进程

// 在main函数中使用 return
// 调用函数 exit();

// linux系统函数
#include <unistd.h>
void _exit(int status);

// 标准c
#include <stdlib.h>
void exit(int status);

4.2 孤儿进程和僵尸进程

父进程创建子进程, 父进程运行结束, 子进程还在运行, 当前的子进程就称之为孤儿进程

  • 进程变成孤儿之后, 有一个进程 PID == 1 (INIT), 操作系统中第一个进程 (操作系统没有桌面终端)
    • init进程会释放孤儿进程的pcb
  • 如果有桌面终端, 孤儿进会被桌面终端对应的进程领养

父进程创建子进程, 子进程运行结束, 父进程还在运行, 这个时候父进程需要回收子进程的pcb资源, 但是父进程没有回收子进程的pcb, 这个时候子进程就变成了僵尸进程.

  • 僵尸进程是已经死了的进程, 只是还占用这一部分系统资源没有释放

4.3 进程回收

防止出现僵尸进程 ------->进程回收(wait,waitpid)

// 需要在父进程中回收已经死亡的子进程资源(pcb)
#include <sys/wait.h>
// 这是一个阻塞函数,  -- 会等待子进程结束, 子进程结束之后该函数解除阻塞
// 			         -- 所有子进程回收完成, 该函数解除阻塞
// 每调用一次这个函数就可以回收一个子进程资源, 如果有多个子进程需要循环调用wait
pid_t wait(int *status);
参数:
	status: 通过这个参数可以指定进行是如何退出的, 如果不想知道写NULL
返回值:
	成功: 返回回收的子进程的进程ID   失败: -1

pid_t waitpid(pid_t pid, int *status, int options);
参数:
	- pid:
		<-1: 取pid的绝对值, 这个值代表进程组的组ID, 代表会在这个进程组的所有的子进程
        -1: 回收任何子进程   ---> 比较常用
        0: 回收当前进程组的所有子进程
        >0: 回收指定的子进程   ---> 有时候用
     - status: 和wait的参数status是一样的
       	- 判断是不是正常退出:
             - WIFEXITED(status): 判断进程是不是正常退出, 如果返回值为1, 正常退出
	             - WEXITSTATUS(status): 如果是正常退出, 得到退出时候返回值的状态码
	                return 状态码;	// 在main函数中
	                exit(状态码)
         - 判断是不是被信号杀死的:
			- WIFSIGNALED(status): 判断进程是不是被信号杀死的, 如果是返回1,被信号杀死
	            - WTERMSIG(status): 假设是被信号杀死的, 得到这个信号值
     - options: 控制当前函数阻塞函非阻塞
         - 0: 当前函数是阻塞的和wait一样
         - WNOHANG: 非阻塞
返回值:
	成功:
		>0: 回收的子进程对应的pid 
		=0: 这个函数是非阻塞函数, 调用这个函数没有子进程退出, 返回0
    失败: -1
        回收资源处了问题, 失败/没有子进程可以回收了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值