8.2 进程标示

ID0的进程通常是调度进程(交换进程),属于内核的一部分。
ID1的进程是init进程,在自举过程结束时由内核调用,该进程读写系统初始化文件,将系统引导至一个状态(如多用户)。 它是一个普通用户进程,但以超级用户特权运行。

8.3 函数fork

函数声明:

#include <unisted.h>
pid_t fork();

特性

  • fork函数被调用依次,返回两次

  • 父进程的所有文件描述符被复制到子进程,即父子进程每个打开的文件描述符共享一个文件表项。一个重点是父子进程共享一个文件偏移量。
    clipboard.png

  • 注意子进程继承了父进程的哪些资源以及两者之间的不同

子进程的继承

  • 继承

       实际用户ID、有效用户ID、实际组ID、有效组ID
       设置用户ID标志和设置组ID标志
       附加组ID
       会话ID
       控制终端
      
       当前工作目录、根目录
       环境
       文件模式的创建屏蔽字
       共享存储段
       资源限制
    
       信号屏蔽和安排
       对任一打开文件描述符的执行时关闭(close-on-exec)标志
  • 不继承

       进程ID
       子进程的运行时间信息
       
       父进程设置的文件锁
       父进程的未处理信号集
       父进程的未处理闹钟
    

8.4 函数 vfork

特性

  • 在子进程调用execexit之前,它在父进程的空间中运行

  • vfork的使用要慎重:在子进程调用execexit之前,子进程若修改数据,则父进程的数据也会改变。

  • vfork保证子进程先运行,在它调用execexit之后父进程才可能被调用运行。

8.5 函数exit

正常终止

  • main函数中return返回

  • 调用exit()

  • 调用_Exit()、_exit()

  • 最后一个线程返回

  • 最后一个线程调用phread_exit()

异常终止

  • 调用abort

  • 进程收到某些信号,使进程退出

  • 最后一个线程对取消做出反应 pthread_cancel()

进程终止时保留的资源

  • 进程ID

  • 该进程的终止状态

  • 该进程使用的CPU时间总量

僵尸进程
子进程终止,但父进程没有利用wait或waitpid获取子进程终止状态
避免出现僵尸进程的方法:
---1. 用wait或waitpid回收终止进程的资源
---2. 编写如下代码

int main(){
    pid_t pid1;
    if ((pid = fork) == 0){ // for simplicity, not take "pid < 0" into consideration
        pid_t pid2;
        if ( (pid2 = fork()) == 0){
            while(1){
               /* grandchild func*/
            }
        }
        exit(0);
    }
    if (wait(NULL) != pid1)
        err_sys("wait err.");

    while(1){
        /*main thread func*/
    }
    exit(0);
}

代码示意图
child1提前终止时,child2的父进程变成了init,当child2终止时,init调用wait回收僵尸进程的资源
clipboard.png

8.6 函数wait和waitpid

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

pid:
---1. pid == -1 ,等待任意进程
---2. pid > 0 , 等待进程pid
---3. pid == 0 , 等待本进程组的任意进程
---4. pid < -1, 等待组ID等于pid绝对值的任一进程

option:
---1. WNOTHANG 没有进程报告状态则立即返回
---2. WCONTINUED
---3. WUNTRACED 子进程由于SIGTTIN、SIGTTOU、SIGTSTP或SIGSTOP信号进入暂停状态 
---4. 0  

status:
clipboard.png

返回值
wait: 唯一的出错是进程没有子进程,errno = ECHILD
waitpid: 指定的进程或进程组不存在或没有权限调用,则会出错

8.7 函数waitid

8.8 函数wait3和wait4

8.10 函数exec

六个exec最终调用execve函数
v: vector
l: list
e:environment
p:path (not pathname)
clipboard.png

基本的进程控制原语: fork, exec, wait, exit
execl execle execlp的命令行参数格式:
char* arg0, char* arg1, ..., char* argn, (char*)0

新程序从调用进程继承的属性:
进程ID和父进程ID
实际用户ID和实际组ID 注意:SUID没有继承
添加组ID
进程组ID
对话期ID
控制终端
当前工作目录
根目录
资源限制
闹钟尚余留的时间
文件方式创建屏蔽字
文件锁
进程信号屏蔽
未决信号
tms_utime, tms_stime, tms_cutime以及tms_ustime值

8.11 更改用户ID和更改组ID

int setuid(uid_t uid);
int setgid(gid_t uid);

int seteuid(uid_t uid);
int setegid(gid_t uid);

int setreuid(uid_t ruid,uid_t euid); 
int setregid(uid_t ruid,uid_t euid);

int getresuid(uid_t ruid,uid_t euid,uid_t suid);
int getresgid(uid_t rgid,uid_t egid,uid_t sgid);

clipboard.png

ruid、euid、suid转换
clipboard.png


shiyang6017
158 声望59 粉丝