C语言进程

什么是进程

什么是程序

一组可以被计算机直接识别的 有序 指令 的集合。

通俗讲:C语言编译后生成的可执行文件就是一个程序。

那么程序是静态还是动态的?

程序是可以被存储在磁盘上的,所以程序是静态的。

那什么是进程

进程是程序的执行过程,是动态的,随着程序的使用被创建,随着程序的结束而消亡。

可以说进程是一个独立的可调度的任务。

进程是系统调度的独立任务。

进程是程序执行的独立任务。

进程是资源(内存资源)管理的最小任务。

一个程序可以只有一个进程,此时正在运行的这个程序也叫进程。

一个程序也可以有多个进程,此时正在运行的这个程序有多个进程动态执行。

所以说进程可以是程序,但程序不一定是进程。

注意:每一个程序运行时,操作系统分配给进程的 是虚拟内存,意味着每一个进程所使用的空间都是虚拟内存, 虚拟内存会被单元管理模块(MMU)映射到物理内存上,如何映射是操作系统关心的事情,程序开发者不用关心。

时间片

进程有多个,而CPU只有一个,假设该CPU是单核的,那么在某一时刻CPU只能处理一个进程,但是不能一直去处理这个进程,得多个进程之间轮流处理,给用户感觉这些进程在同时进行,而CPU处理一个进程的时间段即时间片。时间片是约定好CPU处理一个进程的时间段。

进程的类型

交互进程:完成人机交互的进程,比如shell

批处理进程:比如gcc的四步流程

守护进程:开机自启动,关机自动关闭(后台运行)

进程的状态

就绪状态:具备运行条件,等待处理器运行的进程。

当进程已分配到除CPU以外的所有必要资源后,只要再获得CPU,便可立即执行,进程这时的状态称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列。

运行状态:处理器正在运行的进程。

等待状态:又称阻塞态或睡眠态,指进程不具备运行条件,正在等待某个时间完成的状态。

也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。

死亡状态:运行结束的进程。

进程的模式

终端:内核发送的信号。

系统调用:调用操作系统提供给用户来访问硬件的一组接口。

进程三态模型

运行态→等待态:等待使用资源;如等待外设传输;等待人工干预。

等待态→就绪态:资源得到满足;如外设传输结束;人工干预完成。

运行态→就绪态:运行时间片到;出现有更高优先权进程。

就绪态---→运行态:CPU 空闲时选择一个就绪进程。

孤儿进程

指父进程先于子进程退出,此时子进程称为孤儿进程。但是该进程会被pid为1的init进程收养。

僵尸进程

指子进程先于父进程退出并且没有被父进程回收子进程的资源。此时子进程就会变成僵尸进程。僵尸进程会造成浪费空间、资源泄露等问题。

进程的相关系统调用

创建进程

  1. 每个进程都由父进程创建。
  2. 通过系统调用函数 fork() 实现进程创建。

fork()

头文件:<sys/types.h> <unistd.h>

函数原型:pid_t fork();

返回值:PID,进程ID号。返回 0 表示子进程,返回-1失败,返回大于0的整数表示创建进程的PID。

可以通过getpid()来获取当前运行的进程ID,通过getppid()获取当前进程的父进程ID。

wait()

头文件:<sys/wait.h><sys/types.h>

函数原型:pid_t wait(int* status) status为空时表示忽略子进程退出时的状态,不为空表示保存子进程退出时的状态。

返回值:成功返回子进程的PID,失败返回-1

使进程进入阻塞状态。

直到任意子进程结束或者该进程接收到信号为止。

如果该进程没有子进程,或子进程已经结束。wait()会立即返回。

此函数时进程阻塞时父进程什么也不干。

该函数可以获取子进程终止使的退出状态。

waitpid()

函数原型:pid_t waitpid(pid_t pid, int *status, int options)

入参:pid

pid 传-1时 等待任意子进程与wait功能一样。

pid 传0时 等待其组ID等于调用进程的组ID的任意子进程。

pid 传 小于-1时 等待其组ID等于PID的绝对值的任意子进程。

入参:status 同wait

status 通过WIFEXITED宏来测验 子进程正常退出返回true,否则返回false

status 通过WEXITSTATUS宏 来查看退出状态值。

return exit() _exit() 在WIFEXITED看来都算正常退出

入参:options

传0 同wait 阻塞父进程

传WNOHANG:若由PID指定的子进程并不立即可用,则waitpid不会被阻塞,此时返回值为0,子进程结束时返回子进程PID

返回值:正常返回结束的子进程PID,-1失败,

功能与wait类似。

可以指定等待某个子进程以及等待方式(阻塞或非阻塞)

wait和waitpid都可以实现对子进程资源的回收

exit(int status)

status:退出状态。

使进程终止,并清空缓冲区。

_exit(int status)

使进程终止,但是不会清空缓冲区。

Exec函数族

以exec开头的一系列函数

该族函数提供了在一个进程中执行新的进程

通过fork开启的子进程中拥有与父进程相同的代码,但是开辟了新的空间,这么做实际意义不大。所以exec族函数可以对fork创建的子进程进行代码替换,只保留PID不变,这就实现了在一个进程中产生了新的进程。

参数 意义
l(list) 参数地址列表,以空指针结尾
v(vector) 存有各参数地址的指针数组的地址
p(path) 按 PATH 环境变量指定的目录搜索可执行文件
e(environment) 存有环境变量字符串地址的指针数组的地址

守护进程

  1. 运行在后台的进程,与终端没有任何关系。
  2. 开机自启动,关机自关闭。

前台进程

和终端有关系的进程

后台进程

与终端脱离关系。

变成后台进程的步骤

  1. 首先变成孤儿进程。
  2. 让自己成为新的进程组组长。
  3. 让自己成为新的会话组组长。
  4. 使控制终端tty变成 '?' 才能完全脱离终端。

创建守护进程的步骤

  1. 创建子进程父进程退出。(为了让子进程先被init收养)

  2. 创建新的会话组。(通过setsid()函数)让自己成为新的会话组组长。

此时守护进程已经创建,但是还需要优化。再使用chdir()函数修改守护进程的工作路径。

重设文件掩码。将文件掩码设置为0可以增加守护进程的灵活性

关闭父进程继承过来的文件描述符。因为守护进程用不到这些资源,会造成资源浪费。

  1. getdtablesize()返回一个进程可以打开的最大文件数

  2. 再到/etc/rc.local 文件中exit 0之前 将这个守护进程的绝对路径写在这里。开机自启动。

相关推荐
运维&陈同学1 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
シ風箏2 小时前
Neo4j【环境部署 02】图形数据库Neo4j在Linux系统ARM架构下的安装使用
linux·数据库·arm·neo4j
ZVAyIVqt0UFji4 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡
Cachel wood4 小时前
Vue.js前端框架教程8:Vue消息提示ElMessage和ElMessageBox
linux·前端·javascript·vue.js·前端框架·ecmascript
小屁不止是运维7 小时前
麒麟操作系统服务架构保姆级教程(二)ssh远程连接
linux·运维·服务器·学习·架构·ssh
gavin_gxh8 小时前
SAP PP ECN CSAP_MAT_BOM_MAINTAIN
运维·经验分享·其他
黑客K-ing8 小时前
网络安全防范
linux·服务器·web安全
这题怎么做?!?9 小时前
ARP协议及其具体过程
运维·服务器·网络
Lay_鑫辰9 小时前
禾川HCQ1系列PAC脉冲控制步进驱动器
运维·人工智能·单片机·嵌入式硬件·自动化
卡卡大怪兽9 小时前
fastAPI接口的请求与响应——基础
服务器·网络·fastapi