《UNIX环境高级编程》八进程控制读书笔记

1、进程标识

  • 每个进程都有一个非负整形表示的唯一进城ID。
  • ID为0的进程通常是调度进程,常常被称为交换进程。该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程。
  • 进程ID1通常是init进程,在自举过程结束时由内核调用。init进程决不会终止,它是一个普通的用户进程,但以超级用户特权运行。
#include <unistd.h>
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

2、函数fork

创建一个新进程:

#include <unistd.h>
pid_t fork(void);
//子进程返回0,父进程返回子进程ID;若出错,返回-1
  • fork函数被调用一次,但返回两次。
  • 子进程和父进程继续执行fork调用之后的指令。
  • 子进程是父进程的副本,子进程获得父进程数据空间、堆和栈的副本。父进程和子进程共享正文段。

注ex:在fork之前调用了printf,当调用fork时,printf的数据仍在缓冲区中,然后在将父进程数据空间复制到子进程中时,该缓冲区数据也被复制到子进程中,此时父进程和子进程各自有了带该行内容的缓冲区。

文件共享

fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中。父进程和子进程每个相同的打开描述符共享一个文件表项。
这里写图片描述

在fork之后处理文件描述符有以下两种常见的情况:
(1) 父进程等待子进程完成。在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的文件偏移量已做了相应更新。
(2)父进程和子进程各自执行不同的程序段。

3、函数vfork

vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会引用该地址空间。不过在子进程调用exec或exit之前,它在父进程的空间中运行。
vfork和fork之间的另一个区别是:vfork保证子进程先运行。

4、函数exit

  • 不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。
  • 在任意一种终止情况下,内核为每个终止子进程保存了一定量的信息,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。
  • 对于父进程已经终止的所有进程,它们的父进程都改变为init进程。我们称这些进程由init进程收养。
  • 一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占有的资源)的进程被称为僵死进程。

5、函数wait和waitpid

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。父进程可以选择忽略该信号,或者提供一个该信号发生时即被调用执行的函数(信号处理程序)。

#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid,int *statloc,int options);
//若成功,返回进程ID;若出错,返回0
  • 如果子进程已经终止,并且是一个僵死进程,则wait立即返回并取得该子进程的状态;否则wait使其调用者阻塞,知道一个子进程终止。如调用者阻塞而且它有多个子进程,则在其某一子进程终止时,wait就立即返回。
  • 终止进程的终止状态存放在statloc指向的单元内。

这里写图片描述
这里写图片描述

这里写图片描述

6、函数waitid

#include <sys/wait.h>
int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options);
若成功,返回0;若出错,返回-1

这里写图片描述

7、函数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 option,struct rusage *rusage);
若成功,返回进程ID;若出错,返回-1

参数rusage允许内核返回由终止进程及其所有子进程使用的资源概况。资源统计信息包括用户CPU时间总量、系统CPU时间总量、缺页次数、接收到信号的次数等。

8、函数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,const char *arg0,.../*(char *)0 */);

int execvp(const char *filename,char *const argv[]);

int fexecve(int fd,char *const argv[],char *const envp[]);
若出错,返回-1;若成功,不返回
  • 用fork函数创建新的子进程后,子进程往往要调用一种exec函数以执行另一个程序。
  • 调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。

当指定filename作为参数时:
- 如果filename中包含/,则就将其视为路径名;
- 否则就按PATH环境变量,在它所指定的各目录中搜寻可执行文件。

注:在exec前后实际用户ID和实际组ID保持不变,而有效ID是否改变则取决于所执行程序文件的设置用户ID位和设置组ID位是否设置。

9、更改用户ID和更改组ID

#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
若成功,返回0;若出错,返回-1

更改用户ID的规则(适用于组ID):
(1)若进程具有超级用户特权,则setuid函数将实际用户ID、有效用户ID以及保存的设置用户ID设置为uid。
(2)若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不更改实际用户ID和保存的设置用户ID。
(3)如果上面两个条件都不满足,则errno设置为EPERM,并返回-1。

#include <unistd.h>
int setreuid(uid_t ruid,uid_t euid);//交换实际用户ID和有效用户ID的值
int setregid(gid_t rgid,gid_t egid);
若成功,返回0;若出错,返回-1
  • 一个非特权用户总能交换实际用户ID和有效用户ID。
#include <unistd.h>
int seteuid(uid_t uid);
int setegid(gid_t gid);
若成功,返回0;若出错,返回-1
  • 一个特权用户可将其有效用户ID设置为其实际用户ID或其保存的设置用户ID。

10、解释器文件

不太懂。

11、函数system

#include <stdlib.h>
int system(const char *cmdstring);

因为system在其实现中调用了fork、exec和waitpid,因此有3种返回值:
(1)fork失败或者waitpid返回除EINTR之外的出错,则system返回-1,并且设置errno以指示错误类型。
(2)如果exec失败(表示不能执行shell),则其返回值如同shell执行了exit(127)一样。
(3)否则所有3个函数都成功,那么system的返回值是shell的终止状态,其格式已在waitpid中说明。
注:决不应当在一个设置用户ID程序用调用system,是一个安全性方面的漏洞。

12、进程会计

大多数UNIX系统提供了一个选项以进行进程会计处理。启用该选项后,每当进程结束时内核就写一个会计记录。开机记录一般包括命令名、所使用的CPU时间总量、用户ID和组ID、启动时间等。

会计记录结构定义在头文件《sys/acct.h>中:

typedef u_short comp_t;
struct acct
{
char ac_flag;
char ac_stat;
uid_t ac_uid;
gid_t ac_gid;
dev_t ac_tty;
time_t ac_btime;
comp_t ac_utime;
comp_t ac_stime;
comp_t ac_mem;
comp_t ac_io;
comp_t ac_rw;
char ac_comm[8];
};

这里写图片描述

13、进程调度

进程可以通过调整nice值选择以更低优先级运行。只有特权进程允许提高调度权限。NZERO是系统默认的nice值。

#include <unistd.h>
int nice(int incr);//获取或更改进程的nice值。
若成功,返回新的nice值NZERO;若出错,返回-1
  • 使用这个函数,进程智能影响自己的nice值,不能影响任何其他进程的nice值。
  • incr参数被增加到调用进程的nice值上。如果nice调用成功,并且返回值为-1,那么errno仍然为0。如果errno不为0,说明nice调用失败。
#include <sys/resource.h>
int getpriority(int which,id_t who);
若成功,返回-NZERO~NZERO-1之间的nice值,若出错,返回-1

which参数:
PRIO_PROCESS表示进程
PRIO_PGRP表示进程组
PRIO_USER表示用户ID

如果who参数为0,表示调用进程、进程组或者用户。

setpriority函数可用于为进程、进程组和属于特定用户ID的所有进程设置优先级。

#include <sys/resource.h>
int setpriority(int which,id_t who,int value);
若成功,返回0;若出错,返回-1.
  • value增加到NZERO上,然后变为新的nice值。

14、进程时间

任一进程都可调用times函数获得它自己以及已终止进程的墙上时钟时间、用户CPU时间和系统CPU时间:

#include <sys/times.h>
clock_t times(struct tms *buf);
若成功,返回流逝的墙上时钟时间;若出错,返回-1
struct tms{
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
}

所有由此函数返回的clock_t值都用_SC_CLK_TCK(由sysconf函数返回的每秒时钟滴答数)转换称秒数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值