进程控制

重点:

  • 进程的概念
  • 进程的内存映像
  • 进程控制操作

进程控制

在进程之前首先有并发与并行的答题概念:
①并发:在一个时间段上,CPU处理不同的进程。并发是一个时间段上的概念
②并行:在一个时间点,CPU做同一个事情

多进程的实现:这里假设为单核,这要讨论并发。CPU在一个时间段内,处理不同的进程,由于CPU处理的速度非常快,在用户看来就是连续的画面,所以就实现了多进程。可以想象为很多人要喝水,但饮水机只有一个,所有人排成一队,队首的人接一点水然后排到队尾,第二个人再接一点水,以此类推,最后所有人都可以接上水。
在这里插入图片描述

1. 进程概念

进程是操作系统的系统资源分配的基本单位。进程是启动的程序,数据都在内存中,占用CPU和物理内存。

进程与程序的区别为进程是动态的。进程是运行中的程序,程序是储存在硬盘上的可执行代码。

1.1 进程的基本属性

进程的基本属性包括:进程号(PID)、父进程号(PPID)、进程组号(PGID)、真实用户号(UID)、真实组号(GID)、有效用户号(EUID)、有效用户组号(EGID),以及进程所占有的内存区域、打开的文件描述符和进程环境等。

	获取进程ID: pid_ t getpid()
	获取父进程ID: pid_t getppid()
	获取进程的实际用户:pid_t getuid()
	获取进程的有效用户:pid_t geteuid()
	获取进程的实际组: pid_t getgid()
	获取进程的有效组: pid_t getegid()

返回类型为 pid_t ,其实就是 int ,重新定义是为了让代码的可读性更高
重新定义的过程:
typedef     __pid_t     pid_t
__STD_TYPE     __PID_T_TYPE     __pid_t
#define     __STD_TYPE     typedef
#define     __PID_T_TYPE     __S32_TYPE
#define     __S32_TYPE     int

1.2 进程结构

进程控制块(pcb):进程控制块中储存这一个进程的很多信息,主要有:进程id,进程状态,进程切换时需要保存和恢复的CPU寄存器,虚拟空间的信息,控制终端的信息,当前的工作目录,文件描述符表,会话和进程组。
linux进程用户区主要由3部分组成:代码段、数据段和堆栈段
在这里插入图片描述

2 进程状态

·(R runnable) 运行状态:正在运行或正在等待运行
· (S sleeping)可中断等待状态:进程正在等待某个时间完成。等待过程中可以被信号或定时器唤醒
· (D uninterrruptible sleep)不可中断等待状态:进程正在等待某个时间完成,在等待中不可以被信号或定时器唤醒,必须等再知道等待的事件发生
· (Z zomble)僵死状态: 进程已终止,但进程描述符依然存在,知道父进程调用 wait() 后释放
· (T traced or stopped)停止状态:进程因为收到 SIGSTOP、SIGSTP、SIGTIN、SIGTOU 信号后停止运行或者该进程正在被跟踪(调试程序是,进城处于被跟踪状态)

3. 进程控制操作

3.1 创建进程

1.fork() 创建新进程,linux下所有的进程都是由进程 init 创建的。执行成功时,在父进程中返回子进程的 PID,类型为 pid_t,在子进程中返回0。执行失败返回 -1。fork函数和一般的函数不同,有两个返回值,在父子进程中的返回值不同,这样以区分父子进程。

2.vfork,vfork() 创建的子进程与父进程共享代码以及数据段。

孤儿进程:一个子进程的父进程先结束,该子进程就成为一个孤儿进程,它由init收养。
僵尸进程:子进程结束,父进程还存在,父进程不释放pcb,子进程就成为僵尸进程。僵尸进程是一个死进程,也就是已经运行结束。父进程结束,释放子进程的pcb,僵尸进程就能被杀死。

3.刚 fork 出来之后,父子进程的两个地址空间用户区数据完全相同,后续各自进行不同的操作。
各个进程的地址空间中的数据是完全独立的。
进行读操作时,映射到物理内存共享
进行写操作时,物理内存中复制一份

总结:fork 出来后,后续父子进程进行的操作,互不影响。读时共享,写时复制

3.2 exec函数族

1.让父子进程执行不相同的操作
2.等够替换进程地址空间中的源代码.text段。
3.执行另一个程序不需要创建额外的地址空间,使用子进程的地址空间,在当前程序中调用另一个应用程序

exec之前需要 fork(),创建子进程

这里介绍函数族中两的两个函数:

①execl:执行指定目录下的程序,通常执行自定义的应用程序
int execl(const char *path, const char *arg,…);
第一个 arg :占位
后边的 arg :命令的参数
参数写完之后:NULL
举例:execl("/home/huloves/my_ls", “my_ls”, “-l”);

②execlp:执行PATH环境变量能够搜索到的程序,执行系统自带的应用程序,/bin
int execlp(const char *file, const char *arg, …);
file:执行的命令名字,如 “ls”
举例:execlp(“ls”,“ls”, “-l”);

返回-1调用失败,exec函数族不需要返回值,如果函数执行成功不返回,执行失败就打印错误输出并退出程序

4. 进程回收

1.wait(阻塞函数):pid_t wait(int *wstatus);
①参数status:判断子进程是如何结束的,正常退出或被某信号杀死。
②返回值:

  • -1:回收失败,说明没有子进程了
  • 回收子进程的pid
  • 0:等待进程组ID等于调用进程ID的任何子进程。

③注:调用一次该函数只能回收一个子进程

子进程退出的状态–传出参数
1.WIFEXITED(status):为非0,进程正常退出
WEXITSTATUS(status):如果上宏为真,使用此宏,获得进程退出状态(exit/return)的参数
2.WIFSIGNALED(status):为非0,进程异常终止
WTERMSIG(status):如果上宏为真,使用此宏,获取石金成终止的那个信号的编号

		pid_t wpid;
        while((wpid = wait(&status)) != -1);/
            if(wpid == 0){
                continue;
            }
            printf("died pid = %d\n", wpid);
            if(WIFEXITED(status)){
                printf("return %d\n", WEXITSTATUS(status));
            }
            else if(WIFSIGNALED(status)){
                printf("signed%d\n", WTERMSIG(status));
            }
        }

2.pid_t waitpid(pid_t pid, int *wstatus, int options);
函数作用:同wait函数

参数:
①pid:

  • pid == -1,等待任意子进程。与wait相同
  • pid > 0,等待进程ID与pid相等的子进程
  • id == 0,等待其组ID等于调用进程的组id的任意进程(回收当前组所有的子进程)
  • pid < 0(子进程的pid取反),等待其组ID等于pid的绝对值的任意子进程
    ②status:子进程的退出状态,用法与wait相同
    ③option:设置为WNOHANG,waitpid非阻塞;设置为0,waitpid阻塞

返回值:

  • 大于0:返回清理掉的子进程ID
  • -1:无子进程,回收失败
  • ==0:非阻塞,参3为WNOHANG,子进程正在运行
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值