APUE(第八章)进程控制
进程标识
每个进程都有一个非负整型表示的唯一ID。
由于进程ID总是唯一的,可将其用作其他标识符保证唯一性,比如用进程ID作为名字的一部分创建一个唯一的文件名
进程ID是唯一的但是可以复用。
当一个进程终止后,其进程ID就成为复用的候选者
,大多数系统都有延时算法,使得赋予新建进程得ID不同于最近终止进程所使用得ID。防止将新进程误认为使用同一ID的某个已终止进程
系统中有一些专用进程
ID为0的进程称为
调度进程,或者叫交换进程
,该进程是内核的一部分,并不执行磁盘上的程序,也被称为系统进程
ID为1的通常是init进程
,在自举
(计算机科学导论:第七章 操作系统_、什么是 操作系统 自举?_)过程结束后由内核调用,该进程早期是/etc/init
,较新的版本是/sbin/init
,此进程负责在内核自举后启动一个unix系统
#include <unistd.h>
pid_t getpid(void);//返回进程ID
pid_t getppid(void);//返回父进程ID
pid_t getuid(void);//返回实际用户ID
pid_t geteuid(void);//返回有效用户ID
pid_t getgid(void);//返回实际组ID
pid_t getegid(void);//返回有效组ID
函数fork
创建一个新的进程
#include <unistd.h>
pid_t fork(void);//返回值:子进程返回0,父进程返回子进程ID 若出错-1
由fork创建的新进程被称为子进程
fork被函数调用一次,但返回两次
子进程返回0
父进程返回子进程ID
子进程是父进程的副本,并不共享存储空间部分
父进程与子进程共享正文段
读时共享,写时复制
文件共享
- 父进程重定向标准输出时,子进程的输出也被重定向
- 父进程的所有打开文件描述符都被复制到子进程里
- 父子进程与子进程每个相同的打开描述符共享一个文件表项
- 父子进程共享同一个文件偏移量
fork处理后两种常见情况
子进程继承父进程的东西
- 实际用户ID,实际组ID,有效用户ID,有效组ID
- 附属组ID
- 进程组ID
- 会话ID
- 控制终端
- 设置用户ID标志和设计组ID标志
- 当前工作目录
- 根目录
- 文件模式和创建屏蔽字
- 信号屏蔽和安排
- 对任一打开文件描述符关闭标志
- 环境
- 连接共享存储段
- 存储影像
- 资源限制
父子进程区别如下
- fork返回值不同
- 进程ID不同
- 这两个进程父进程ID不同:子进程的父进程ID是创建它的进程ID,而父进程的父进程ID不变
- 子进程tms_utime、tms_stime、tms_cutime和tms_ustime的值设置为0、
子进程不继承父进程的文件锁
- 子进程的未处理闹钟被清除
- 子进程未处理信号集设为空集
fork失败原因
- 系统已经有太多进程
- 该进程实际用户ID进程总数超过了系统限制
CHILD_MAX规定,每个实际用户可拥有的最大进程数
fork有以下两种用法
- 父进程希望复制自己父进程和子进程执行不同的代码段。例如,网络服务父进程等待客户端的服务请求,请求到达时,父进程调用fork使子进程处理此请求,父进程继续等待请求
- 一个进程要执行不同的程序。通常方法是调用exec函数族,这种方法称为spawn
函数vfork
vfork函数的调用序列和fork相同,但二者语义不同
函数exit
详细介绍了进程终止
孤儿进程
- 如果父进程在子进程之前终止,该父进程的所有子进程的父进程都改变为init(ID 为1)进程,我们称这些进程有init收养,具体过程如下
- 子进程结束时也会由init进程完成对它的状态收集工作
- 子进程结束时也会由init进程完成对它的状态收集工作
僵死进程
简单来说,父进程未结束,子进程已结束,但父进程未给子进程收尸
函数wait和waitpid
子进程在终止时内核向其父进程发送SIGHLD信号
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);//两个函数返回值,成功返回ID,出错返回0
调用上述函数会发生如下情况
- 如果其所有子进程都还在运行,则阻塞
- 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回
- 如果他没有任何子进程,则立即出错返回
这两个函数区别
- 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞
- waitpid并不等待在其调用之后的第一个终止子进程,有若干个选项,可以控制他所等待的进程
- 如果子进程已终止,并且是一个僵死进程,则wait立即返回并取得该子进程的状态,否则wait使调用者阻塞,直到一个子进程终止。
- statloc是一个整型指针,若statloc不为空指针,则终止状态就存放在它所指向的单元内,若不关心终止状态,该参数可指定为空指针
下面4个互斥宏可用来取得进程终止原因,这四个宏哪一个为真就可以选用其他宏来取得退出状态、信号编号等
等待特定进程的函数waitpid
pid==-1waitpid与wait等效
pid>0 等待进程ID与pid相等的进程
pid==0等待组ID等于调用进程组ID的任一子进程
pid<-1等待组ID等于pid绝对值的任一子进程
options为0或者下标按位或
函数waitid
SUS提供,此函数类似于waitpid
#include <sys/wait.h>
int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options);//成功返回0,出错-1
idtype
常量
options常量
函数wait3和wait4
允许内核返回由终止进程及其所有子进程使用资源的情况
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>pid_t wait3(int *statloc,int options,struct rusage *rusage);
pid_t wait4(pid_t pid,int *statloc,int options,struct rusage *rusage);
rusage结构体如下
竞争条件
当多个进程都企图对共享数据进行某种处理,而最后取决于进程运行的顺序时,我们认为发生了竞争条件
fork后不能确定哪个进程先运行
为避免竞争条件和轮询,在多个进程之间需要有某种形式的信号和接收方法
函数exec
当进程调用exec函数时,该进程执行的程序完全替换新程序
- 因为exec并不创建新进程,所以前后的进程ID并未改变
- exec是用磁盘上的一个新程序替换了当前进程的正文段,数据段,堆段和栈段
7种不同的exec
#include <unistd.h>
int execl(const char *pathname,const char *arg0,.../*(char *)0*/);
int execv(const char *pathname,char *const argv[]);
int execle(const char *pathname,const char *arg0,.../*(char *)0,char *const envp[]*/);
int execve(const char *pathname,char *const argv[],char *const envp[]);
int execlp(const char *filename,char *const argv0,.../*(char *)0*/);
int execvp(const char *filename,char *const argv[]);
int fexecve(int fd,char *const argv[],char *const envp[]); //成功不返回,出错-1
如果filename中包含/,则就将其视为路径名
否则就按
PATH(PATH是一个环境变量,名为PATH)
环境变量,在它所指定的个目录搜寻可执行文件
*execlp或execvp使用路径前缀的一个找到了可执行文件,但是该文件不是由连接编辑器产生的可执行文件,则就认为该文件是一个可执行脚本,尝试用/bin/sh解释,并以该filename作为shell输入
fexecve
结尾l表示list,v表示矢量vector
- l表示新程序的每个命令行参数都作为一个单独的参数,这种参数以空指针结尾
- v表示用argv[]表示每个命令行参数
- l表示新程序的每个命令行参数都作为一个单独的参数,这种参数以空指针结尾
setenv与putenv,可更改当前环境和后面生成的子进程环境,但不影响父进程的环境
新程序从调用进程继承了以下属性
- 进程ID和父进程ID
- 实际用户ID和实际组ID
- 附属组ID
- 进程组ID
- 会话ID
- 控制终端
- 闹钟尚余留时间
- 当前工作目录
- 根目录
- 文件模式创建屏蔽字
- 文件锁
- 进程信号屏蔽
- 未处理信号
- 资源限制
- nice值
- tms_utime、tms_stime、tms_cutime以及tms_cstime
posix.1明确要求在exec时关闭打开目录流,这通常是由opendir函数实现的,
更改用户ID和更改组ID
最小特权模型,我们程序应当只具有为完成给定任务所需的最小特权
,降低由恶意用户试图哄骗我们的程序以未预料的方式使用特权造成的安全性风险
#include <unistd.h>int setuid(uid_t uid);
int setgid(gid_t gid);//成功返回0出错-1
- 更改用户ID规则
- 若进程有超级用户特权,则setuid函数将实际用户ID、有效用户ID以及保存的设置用户ID设置为uid
- 若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户iD,则setuid只将有效用户ID设置为uid。不更改和保存的设置用户ID
- 以上条件都不满足,则errno设置为EPERM,并返回-1
解释器文件
一种文本文件,起始行是
#!pathname[optional-argument]
,比如#!/bin/sh
函数system
执行字符串命令行
#include <stdlib.h>
int system(const char *cmdstring);
- cmdstring是要执行的命令
- fork失败或者waitpid返回除EINTR之外的错误,system返回-1,并且设置errno以指示错误类型
- 如果exec失败,则其返回值如同shell执行了exit(127)一样
- 若所有的三个函数(fork,exec和waitpid)都成功,那么system的返回值是shell的终止状态,其格式已在waitpid中说明
进程会计
用户标识
系统通常记录用户登录时的名字,用getlogin函数获得此登录名
#include <unistd.h>
char *getlogin(void);//返回指向登录名字符串指针,出错null
进程调度
#include <unistd.h>
int nice(int incr);//成功返回新的nice值NZERO,出错-1;
getpriority函数像nice函数那样获取进程nice值,但getpriority还可以获取一组相关进程的nice值
#include <sys/resource.h>
int getpriority(int which,id_t who);//成功返回-NZERO~NZERO-1 nice值,出错-1
进程时间
任一进程都可以调用times函数获得他自己以及已终止子进程的墙上时钟时间,用户cpu和系统cpu时间
#include <sys/times.h>
clock_t times(struct tms *buf);//成功返回流逝的墙上时钟时间(以时钟滴答为单位);出错-1
tms结构如下
参考:
《APUE》
计算机科学导论:第七章 操作系统_
什么是 操作系统 自举?_
APUE(第八章)进程控制相关推荐
- [单刷APUE系列]第八章——进程控制[1]
目录 [单刷APUE系列]第一章--Unix基础知识[1] [单刷APUE系列]第一章--Unix基础知识[2] [单刷APUE系列]第二章--Unix标准及实现 [单刷APUE系列]第三章--文件I ...
- UNIX高级环境编程—第八章进程控制
第八章-进程控制 1进程相关概念 1.1 程序和进程 1.2 并行和并发 1.3 进程控制块 1.4 进程标志 1.5进程状态(面试考) 2 创建进程 2.1 fork函数 2.2 ps命令和kill ...
- led计数电路实验报告_「正点原子FPGA连载」第八章 按键控制LED灯实验
1)实验平台:正点原子开拓者FPGA开发板 2)本实例源码下载:请移步正点原子官网 第八章 按键控制LED灯实验 按键是常用的一种控制器件.生活中我们可以见到各种形式的按键,由于其结构简单,成本低廉等 ...
- 进程控制概念简介 多线程上篇(三)
进程控制 进程的基本数据信息是操作系统控制管理进程的数据集合,这些信息就是用来控制进程的,此处我们说的进程控制就是进程的管理. 比如进程有状态,那么进程的创建.终止,状态的切换,这都不是进程自主进行的 ...
- UNIX环境高级编程笔记之进程控制
本章重点介绍了进程控制的几个函数:fork.exec族._exit.wait和waitpid等,主要需要掌握的是父进程和子进程之间的运行机制,怎么处理进程的正常和异常终止.以及怎么让进程执行不同的程序 ...
- 8.6 wait和waitpid函数-进程控制
8.6 wait和waitpid函数-进程控制 当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号.因为子进程终止是个异步事件(这可以在父进程运行的任何时候发生),所以这种信号也是内核 ...
- vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制
Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...
- 【linux草鞋应用编程系列】_2_ 环境变量和进程控制
一. 环境变量 应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作. 在linux中有两种方法获取环境变量,分述如下. 1.通过main函数的参数获取环境变量 main函数的多种 ...
- Linux系统状态检测及进程控制--2
Linux系统状态检测及进程控制--1(http://crushlinux.blog.51cto.com/2663646/836481) 4.僵死(进程已终止,但进程描述符存在,直到父进程调用wait ...
最新文章
- centos php sftp 扩展,Linux(CentOS)上配置 SFTP
- 教你打入clr内部: 配置windows上的windbg,linux上的lldb
- gc java root_C#技术漫谈之垃圾回收机制(GC)
- 对Boost.Asio中异步事件循环的理解
- “fatal error C1010”错误解决的三种方法
- 8Manage轻松解决采购过程“脏乱差”问题
- 嫦娥五号回来要打水漂,载人回来怎么办?
- 计算机十个小技巧,Win10的10个实用小技巧,电脑小白轻松掌握,大大提升工作效率...
- 解析yml文件 转换 Map
- 我每年得忽悠10万程序员上车
- Android自带Switch系列汇总学习
- css3缓慢出现,让CSS3旋转开始缓慢然后结束缓慢?
- 刘莹:提升站内搜索的五大必要性
- 在web网页中打开word文档
- 时间片轮转算法的实现
- 模糊集合和隶属度函数--AForge.NET框架的使用(一)
- 企业WiFi解决方案,解决所有后顾之忧
- linux系统如何安装lol,Linux系统下安装红色警戒2步骤详解(2)
- javaAPI 集合
- 宏#define边缘效应(边际效应)
热门文章
- 蚂蚁森林最高效的合种团队,新树冷杉6天合种成员招募
- Nature综述:植物与微生物组的相互作用:从群落装配到植物健康(下)
- 一顿“寄生虫大餐”,或能治好干净引来的免疫病
- pandas编写自定义函数、使用apply函数应用自定义函数基于Series数据生成新的dataframe
- R语言ggplot2可视化散点图、并使用geom_encircle函数自定义多边形圈定可视化图像中的指定区域、使用geom_smooth函数基于loess方法拟合数据点之间的趋势关系曲线
- R语言ggplot2可视化使用ggsave将可视化图像结果保存为SVG文件实战
- R语言deLong‘s test:通过统计学的角度来比较两个ROC曲线、检验两个ROC曲线的差异是否具有统计显著性
- R语言随机森林回归(randomforest)模型构建
- Python使用matplotlib绘图并去除颜色样条colorbar实战:remove colorbar from figure in matplotlib
- R语言SVM支持向量机模型数据分类实战:探索性数据分析、模型调优、特征选择、核函数选择