进程id:
ID 为 0的是调度进程
ID为 1的是init进程,类似于xv6的userinit,
ID 为2的一般是页守护进程, 负责虚拟存储系统的分页操作
子进程是父进程的副本,一定意义上,两者并不共享空间
fork以后,子进程和父进程不一定谁先执行,如果要确定顺序,则需要同步
除了进程ID,进程还有一些标识符,如下:
8.3 fork
因为fork后面尝尝跟随,exec,所以一般不生成副本,而是Copy On write
针对上述代码,文件temp.out内有两个before fork,是因为父进程和子进程的输出缓冲区内容都输出到了文件中
fork之后,父进程和子进程同时操作同一个文件描述符,有两种用法:
(1) 父进程等待子进程完成 。 这种情况下,无需对描述符做任何操作,因为子进程已经对文件偏移量辽更新
(2) 父进程和子进程执行不同的程序段,父进程和子进程各自关闭不需使用的文件描述符
fork的两种用法
(1) 父进程希望复制自己
(2) 一个进程要执行一个不同的程序,就是fork 之后立即调用 exec
8.4 vfork
已被弃用,相对于fork,vfork保证子进程先执行
8.5 函数exit
进程的5中终止方式:
1. main return
2. exit(num) 标准C库函数
3. _exit或者_Exit函数
4. 最后一个线程执行 return
5. 最后一个线程调用pthread_exit
这tm鬼看得下去,我还是去写我的MIT lab4吧。。。。
8.6 函数wait和waitpid
当一个进程异常或者终止时,会向父进程发送SIGCHLD信号,父进程可以选择忽略信号,或者执行某个指定函数,
不能这样,我得画思维导图,不能写博客,博客太散了
wait和waitpid的区别,waitpid可以选择不阻塞,也可以选择要等待的pid,还支持作业啥的
core文件,到底是个啥
wait返回终止子进程的进程ID
8.6 函数wait和waitpid
僵死进程 : 一个已经终止、但是父进程尚未对其进行善后处理(比如释放占用的资源)的进程,成为僵死进程
如果一个进程即将终止,内核会检查进程列表中,哪个进程是它的子进程,如果是,则将该子进程的父进程id改为1(init进程的ID),称为init收养子进程
8.7 waittid
看不下去,。。。
8.10 exec
exec 会跳到一个新函数的main方法去执行,它用磁盘的新程序替换了当前进程的正文段,数据段,堆和栈
exec有7个:
前4个执行,指定路径的可运行文件,
后两个,执行可运行文件或者把文件当成shell脚本来执行
grep getrlimit /usr/share/man/*/*
grep: /usr/share/man/cs/man1: Is a directory
grep: /usr/share/man/cs/man5: Is a directory
grep: /usr/share/man/cs/man7: Is a directory
grep: /usr/share/man/cs/man8: Is a directory
这grep啥意思
echoall 打印命令行参数,以及所有环境变量(environ)
./echoall
argv[0]: ./echoall
SHELL=/bin/bash
SESSION_MANAGER=local/ubun2004:@/tmp/.ICE-unix/1731,unix/ubun2004:/tmp/.ICE-unix/1731
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
XDG_MENU_PREFIX=gnome-
......
exec继承的属性如下:
8.11 更改用户ID和组ID
更改ID的目的,是为了最小权限原则,减少权限过大带来的错误或者危险
通过更改ID(有效用户ID,设置用户ID都行)来提升或者降低用户权限,具体函数为setuid和setgid
设置用户ID 置为1,表示exec可以将当前进程的权限设置为文件所有者的权限
geteuid用来获取有效用户ID
seteuid和setegid用来设置有效用户和组的ID
8.12 解释器文件
以 #! /bin/bash 类似形式开头的文件
这种文件通过exec执行的时候,第一个参数argv[0] 为/bin/bash
也可以是#! /bin/awk -f ,这样第二个参数为-f
代码如下:
#!/usr/bin/awk -f
# Note: on Solaris, use nawk instead
BEGIN {
for (i = 0; i < ARGC; i++)
printf "ARGV[%d] = %s\n", i, ARGV[i]
exit
}
输出如下:
ubuntu@ubun2004:/home/learnApue/apue.3e/proc$ ./awkexample a b c
ARGV[0] = awk
ARGV[1] = a
ARGV[2] = b
ARGV[3] = c
解释器文件不是必须的,但是可以提升效率,至于如何提升,无需知道太多
8.13 system
用来完成一些常用的函数调用,比如获得日期,date,具体如下代码如下:
#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
int status;
if ((status = system("date")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("nosuchcommand")) < 0)
err_sys("system() error");
pr_exit(status);
if ((status = system("who; exit 44")) < 0)
err_sys("system() error");
pr_exit(status);
exit(0);
}
输出如下:
ubuntu@ubun2004:/home/learnApue/apue.3e/proc$ ./systest1
Sun 19 Sep 2021 07:37:06 AM EDT
normal termination, exit status = 0
sh: 1: nosuchcommand: not found
normal termination, exit status = 127
ubuntu :0 2021-09-17 22:20 (:0)
normal termination, exit status = 44
设置用户ID的程序不应该调用system,会产生安全性漏洞
8.14 会计记录
用来记录进程用的CPU时间、用户ID,组ID, 启动时间等,按进程终止的顺序排序
一个会计记录,对应一个进程,一个进程可能会执行多个程序,比如程序 A exec B,B exec C,C exit
先得安装acc
然后执行命令如下:
root@ubun2004:/home/learnApue/apue.3e/proc# ./pracct /var/log/account/pacct | grep dd -C 20
dd e = 0, chars = 0,
test1 e = 200, chars = 0,
apport e = 9, chars = 0, S
test1 e = 410, chars = 0, D X F
test1 e = 600, chars = 0, X F
test1 e = 800, chars = 0, F
pracct e = 0, chars = 0,
e代表时钟滴答数, D X F代表的是ac_flag
8.15 用户标识
getlogin获取
8.16 进程调度
nice 值,标识对CPU的友好程度,nice越高,越友好,优先级越低,CPU占用时间越少
8.17 进程时间
结构体如图
后面两个字段是子进程用的CPU时间,命令如下:
root@ubun2004:/home/learnApue/apue.3e/proc# ./times1 "sleep 5" "date" "man bash >/dev/null"
command: sleep 5
real: 5.05
user: 0.00
sys: 0.00
child user: 0.00
child sys: 0.00
normal termination, exit status = 0
command: date
Sun 19 Sep 2021 08:51:46 AM EDT
real: 0.00
user: 0.00
sys: 0.00
child user: 0.00
child sys: 0.00
normal termination, exit status = 0
command: man bash >/dev/null
real: 0.24
user: 0.00
sys: 0.00
child user: 0.12
child sys: 0.12
normal termination, exit status = 0