APUE进程控制

pag171
ID-----0              通常为调度进程,常常被称为交换进程, 不执行任何磁盘上的程序,也被称为系统进程。
ID-----1              通常为init进程,通常读与系统有关的初始化文件,并将系统引导到一个状态,init进程绝不会终止。(普通用户进程(与交换进程不同,不是内核中的系统进程),但以超级用户特权运行)

pid_t getpid(void);//进程ID
pid_t getppid(void);//父进程ID
uid_t getuid(void);//进程实际用户ID
uid_t geteuid(void);//进程有效用户ID
gid_t getgid(void);//进程实际组ID
gid_t getegid(void);//进程有效组ID

pag172
pid_t fork(void)
子进程返回0                            (一个进程只有一个父进程,总可以调用getppid获得父进程ID)
父进程返回新子进程ID(可能有多个子进程,且没有一个函数使一个进程获得其所有子进程的进程ID)

子进程时父进程的副本:
子进程获得父进程的数据空间,堆和栈的副本。父子进程并 不共享这些 存储空间部分,他们 共享正文段(非存储空间)。
写时拷贝
并不执行父进程数据段,栈和堆的完全拷贝,这些区域由父子进程共享,内核将他们的访问权限改变为只读。当父子进程中任何一个试图改变这些区域时,内核只为修改区域的那块内存制作一个副本。

strlen:包含终止null字节
sizeof:不包含null字节

pag174
在重定向父进程的标准输出时,子进程的标准输出也被重定向。(fork:父进程所有打开文件描述符都被复制到子进程中)

子进程继承的属性
  • 实际用户ID、实际组ID、有效用户ID、有效组ID(进程和用户)(关系到权限)
  • 附加组ID
  • 进程组ID(进程和进程)(不关系到权限)
  • 会话ID
  • 控制终端
  • 设置用户ID标识和设置组ID标识
  • 当前工作目录
  • 根目录
  • 文件模式创建屏蔽字(umask)
  • 信号屏蔽和安排
  • 针对任一文件描述符的在执行时关闭(close on exec)标识
  • 环境
  • 连接的共享存储段
  • 存储映射
  • 资源限制
  • 文件描述符

父子进程间区别

  • fork返回值
  • 进程ID
  • 父进程ID
  • 子进程tms_*部分设置为0
  • 父进程设置的文件锁不会被子进程继承
  • 子进程的未处理闹钟被清除
  • 子进程的未处理信号集设置为空集

vfork :不将父进程地址空间完全复制到子进程中,在子进程调用exec或exit之前,他在父进程的空间中运行。
vfork 保证子进程先运行,在子进程调用exec或exit之前,内核会使父进程处于休眠状态。

pag178
对于 父进程已经终止的所有进程,他们的父进程都改变 为init进程
一个已经终止,但是其父进程尚未对其进行善后处理(获取终止进程的有关信息,释放他仍占用的资源)的进程称为 僵尸进程(调用wait、waitpid获取状态)
init只要有一个子进程终止就会调用一个wait函数取得终止状态,所以不会产生僵尸进程

pag182
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);//WNOHANG可使调用者不阻塞
pid:
-----pid == -1-------等待任意子进程
-----pid > 0    -------等待其进程ID与pid相等的子进程
-----pid == 0--------等待其组ID与等于调用进程组ID的任一子进程
-----pid < -1 --------等待其组ID等于pid绝对值的任一子进程
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
idtype:
P_PID:等待特定进程
P_PGID:等待特定进程组中任一子进程
P_ALL:等待任一子进程

如果一个进程fork一个子进程,但不要他等待子进程终止,也不希望子进程处于僵死状态知道父进程终止,可以调用fork两次,先让父进程wait第一个子进程终止,使第二个子进程被init领养。(init子进程不会成为僵死进程)

pag188
int execl(const char *pathname, const char *arg0, ...);
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ...);
int execve(const char *pathname, char *const argv[], char *const envp[]);//内核系统调用
int execlp(const char *filename, const char *arg0, ...);
int execvp(const char *filename, char *const argv[]);
exec函数:
进程调用此函数时,该进程执行的程序完全替换为新程序,而 新程序则从其main函数开始执行
exec并不创建新进程,所以前后进程ID未改变
exec函数用一个全新的程序 替换了当前进程的正文、数据、堆、栈段
6个exec函数中字符寓意
----p:该函数取filename作为参数,并且用PATH环境变量寻找可执行文件。
----l:该函数取一个参数表,他与字母v互斥//参数表以NULL指针结尾
----v:该函数取一个argv[]矢量。
----e:该函数取envp[]数组,而不使用当前环境

执行exec后保持的属性
  • 进程ID和父进程ID
  • 实际用户ID和实际组ID
  • 附加组ID
  • 进程组ID
  • 会话ID
  • 控制终端
  • 闹钟尚余留时间
  • 当前工作目录
  • 根文件
  • 文件模式创建屏蔽子
  • 文件锁
  • 进程信号屏蔽字
  • 未处理信号
  • 资源限制
  • tms_*
FD_CLOEXEC:进程中每个打开的描述符都有一个 执行时关闭标志。若此标志设置则在执行exec时关闭该描述符,否则该描述符打开。

pag193
int setuid(uid_t uid);//设置实际用户ID和有效用户ID
int setgid(gid_t gid);//设置实际组ID和有效组ID
关于内核维护的三个用户ID,注意:
  1. 只有超级用户进程可以更改实际用户ID。(setuid设置全部三个用户ID)
  2. 仅当对程序文件设置了设置用户ID位时,exec函数才会设置有效用户ID。任何时候都可以调用setuid,将有效用户ID设置为实际用户ID或保存的设置用户ID。
  3. 保存的设置用户ID是由复制有效用户ID而得来的

int setreuid(uid_t ruid, uid_t euid);//交换实际用户ID和有效用户ID

int setregid(gid_t rgid, gid_t egid);//交换实际组ID和有效组ID

int seteuid(uid_t uid);

int setegid(gid_t gid);                                        //pag196设置不同用户ID的各函数


pag200
int system(const char *cmdstring);
在其实现中调用了 fork、exec和waitpid
如果一个进程正以特殊权限(设置用户ID或设置组ID)运行,他又想生成另一个进程执行另一个程序,则他应当 直接使用fork和exec,而且在fork之后,exec之前要改回到普通权限(exec会复制有效ID-》保存设置ID)。设置用户ID或设置组ID程序决不应调用system函数。

char * getlogin(void);//获取登录名
clock_t time(struct tms *buf);

不提供返回保存的设置用户ID(只是供setuid时做为一个参考,看要设置的有效id和保存的设置用户id相不相等)的函数,我们必须在进程开始时保存有效用户ID
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值