关于进程的一些概念

1.程序和进程

程序:程序(program)是存放在磁盘文件中的可执行文件

进程:程序的执行实例被称为进程(process),进程具有独立的权限和职责。如果系统中某个进程崩溃,它不会影响到其余的进程。每个进程运行在其各自的虚拟地址空间中,进程之间可以通过由内核控制的机制相互通讯。

进程ID:每个linux进程都一定有一个唯一的数字标识符,称为进程ID(process ID),简称PID,进程ID总是一非负整数(从0开始计算)。

name$ ps -ef | more                               
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 Mar10 ?        00:37:15 /usr/lib/syst
emd/systemd --switched-root --system --deserialize 22
root          2      0  0 Mar10 ?        00:00:01 [kthreadd]
root          5      2  0 Mar10 ?        00:01:15 [kworker/u144
:0]
root          6      2  0 Mar10 ?        00:00:53 [ksoftirqd/0]
root          7      2  0 Mar10 ?        00:00:17 [migration/0]
root          8      2  0 Mar10 ?        00:00:00 [rcu_bh]
root          9      2  0 Mar10 ?        00:41:44 [rcu_sched]
--More--

2.内核中的进程结构

task_struct ==>结构体 ==>进程表项,记录了当前进程中的信息。

上图中的files_struct是指文件描述符表,实际上就是一个结构体指针

可以自己在linux系统下查看内核的头文件就能看到task_struct结构体,参考下面的方法

name$cd /usr/src
name$ls
linux-headers-2.6.38-8 linux-headers-2.6.38-8-generic
name$cd linux-headers-2.6.38-8/include/linux
name$vim sched.h

3.C程序启动过程

3.1 内核启动特殊例程
3.2 启动例程
  • 在进程的main函数执行之前内核会启动
  • 该例程防止在/lib/libc.so.***中(函数动态库)
    vname$ ls /lib/libc*                     
    /lib/libc-2.17.so
    /lib/libc.a
    /lib/libcap.so.2
    /lib/libcap.so.2.22
    --More--
  • 编译器在编译时会将启动例程编译进可执行文件之中
3.3 启动例程的作用
  • 搜集命令行的参数传递给main函数中的argc和argv
  • 搜集环境信息构建环境表并传递给main函数
  • 登记进程的终止函数

4.进程终止方式

4.1 正常终止
  • 从main函数返回(return 0)
  • 调用exit(标准c库函数)(exit(0))
  • 调用_exit或_Exit(系统调用,由内核提供)
  • 最后一个线程从启动例程返回(一个进程只有一个主线程)
  • 最后一个线程调用pthread_exit
4.2 异常终止
  • 调用abort
  • 接受到一个信号并终止(最常用)
  • 最后一个线程对取消请求做处理响应
4.3 进程返回
  • 通常程序运行成功返回0,否则返回非0
  • 在shell中可以查看进程返回值(echo $?)
4.4 atexit函数
  • 每个启动的进程都默认登记了一个标准的终止函数
    #include<stdlib.h>
    int atexit(void (*function)(void));
    //返回:若成功则为0,若出错则为-1
    //功能:向内核登记终止函数
  • 终止函数在进程终止时释放进程所占用的一些资源
  • 登记的多个终止函数执行顺序是以栈的方式执行,先登记的后执行。
  • 终止函数并非在所有情况下都会被调用(系统调用的_exit不会调用终止函数,也不会刷新缓存·)
    name$ cd process/                        
    name$ mkdir bin include obj src
    name$ ls                        
    bin  include  obj  src
    name$ vim src/process_term.c
    #include<unistd.h>
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<fcntl.h>
    
    //define the stop function for process
    void term_fun1(void)
    {
        printf("First term function\n");
    }
    
    void term_fun2(void)
    {
        printf("Second term function\n");
    }
    
    void term_fun3(void)
    {
        printf("Third trem function\n");
    }
    
    int main(int argc, char *argv[])
    {
        if(argc < 3){
            fprintf(stderr,
                    "usage: %s file [exit|_exit|return]\n", argv[0]);
            exit(1);
        }
       
        //Register termination function with kernel
        atexit(term_fun1);
        atexit(term_fun2);
        atexit(term_fun3);
    
        FILE *fp = fopen(argv[1], "W");
        fprintf(fp, "hello iotek"); //全缓存
        if(!strcmp(argv[2], "exit")){
            exit(0); //标准c的库函数
        }else if(!strcmp(argv[2], "_exit")){
            _exit(0); //系统调用
        }else if(!strcmp(argv[2], "return")){
            return 0;
        }else{
            fprintf(stderr,
             "usage: %s file [exit|_exit|return]\n", argv[0]);
        }
    
        exit(0);
    }
    name$ gcc -o bin/process_term src/process_term.c
    name$ bin/process_term iotek.txt return
    Third term function
    Second term function
    First term function
    name$ more iotek.txt
    hello iotek
    name$ rm -rf iotek.txt
    name$ bin/process_term iotek.txt exit
    Third term function
    Second term function
    First term function
    name$ more iotek.txt
    hello iotek
    name$ rm -rf iotek.txt
    name$ bin/process_term iotek.txt _exit
    name$ ls
    bin include iotek.txt obj src
    name$ more iotek.txt
    name$
4.5 进程终止方式区别

5.进程的启动和退出流程

6.进程查看和进程状态

6.1 用ps指令查看进程信息
  • 通常可以查看到:进程的ID、进程的用户ID、进程状态和进程的command,例如ps -aux;ps -ef等。

USER:进程的属主;

PID:进程的ID

PPID:进程的父进程

%CPU:进程占用的CPU百分比

%MEM:占用的内存百分比

NI:进程的NICE值,数值DA,表示较少占用CPU时间

VSZ:进程虚拟大小

RSS:驻留中页的数量

TTY:终端ID

STAT:进程的状态

WCHAN:正在等待的进程资源

START:启动进程的时间

TIME:进程消耗CPU的时间

CMMAND:命令的名称和参数

name$ ps
   PID TTY          TIME CMD
226411 pts/20   00:00:00 ps
831852 pts/20   00:00:00 bash
name$ echo $SHELL                             # ~/process
/bin/bash
name$ ps -ef | more
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 Mar10 ?        00:37:30 /usr/lib/systemd/
systemd --switched-root --system --deserialize 22
root          2      0  0 Mar10 ?        00:00:01 [kthreadd]
root          5      2  0 Mar10 ?        00:01:15 [kworker/u144:0]
root          6      2  0 Mar10 ?        00:00:53 [ksoftirqd/0]
root          7      2  0 Mar10 ?        00:00:17 [migration/0]
root          8      2  0 Mar10 ?        00:00:00 [rcu_bh]
root          9      2  0 Mar10 ?        00:41:59 [rcu_sched]
root         10      2  0 Mar10 ?        00:00:00 [lru-add-drain]
--More--

UID是进程的属主,PID是进程号,PPID是父进程号

TTY:终端ID

STIME:启动进程的时间

TIME:进程消耗CPU的时间

CMD:命令的名称和参数

6.2 进程常见状态
6.2.1 运行状态
  • 系统当前进程
  • 就绪状态进程
  • ps命令的STAT列为值R
6.2.2 等待状态
  • 等待事件发生
  • 等待系统资源
  • ps命令的STAT列为值S(可中断的等待)或D(不可中断的等待),一般为S
6.2.3 停止状态
  • ps命令的STAT列为值T
6.2.4 僵尸状态
  • 进程终止或结束
  • 在进程表项中仍有记录
  • ps命令的STAT列为值Z
6.3 进程状态切换

7.进程调度

7.1 进程调度步骤
7.1.1 第一步:处理内核中的工作
7.1.2 第二步:处理当前进程
7.1.3 第三步:选择进程
  •  实时进程
  • 普通进程
7.1.4 第四步:进程交换

7.2 task_struct中的调度信息:
7.2.1 策略
  • 轮流策略
  • 先进先出策略
7.2.2 优先权
  • Jiffies变量
7.2.3 实时优先权
  • 实时进程之间(动态优先级)
7.2.4 计数器

7.3 进程状态变化关系(并发)

7.4进程标识
#include<unistd.h>

#include<sys/types.h>

pid_t getpid(void)  //获取当前进程ID

uid_t getuid(void)  //获取当前进程的实际用户ID

uid_t geteuid(void)  //获得当前进程的有效用户ID(很多情况下实际用户就是有效用户,除非切换用户去启动特定权限的进程)

gid_t getgid(void)  //获得当前进程的用户组ID

pid_t getppid(void)  //获得当前进程的父进程ID

pid_t getpgrp(void)  //获得当前进程所在的进程组ID

pid_t getpgid(pid_t pid)  //获得进程ID为pid的进程所在的进程组ID
name$ vim src/process_id.c
#include<unistd.h>
#include<stdio.h>

int main(void)
{
    printf("pid: %d\n", getpid());
    printf("ppid: %d\n", getppid());
    printf("uid: %d\n", getuid());
    printf("euid: %d\n", geteuid());
    printf("user gid: %d\n", getgid());
    printf("gid: %d\n", getpgrp());
    printf("pgid: %d\n", getpgid(getpid()));
    printf("ppgid: %d\n", getpgid(getppid()));

    return 0;
}

name$ gcc -o bin/process_id src/process_id.c 
name$ bin/process_id
pid: 665757
ppid: 665019
uid: 7588469
euid: 7588469
user gid: 64000
gid: 665757
pgid: 665757
ppgid: 665019

name$ ps                         
   PID TTY          TIME CMD
665019 pts/60   00:00:00 bash
668244 pts/60   00:00:00 ps
name$ id                          
uid=7588469(name) gid=64000(user) groups=64000(user),25991(ugpdupccom),26220(ugpdupcgw),26223(ugpdupcinf),10004555(ugpdupcup)

//当前euid和uid是一样的,都是7588469,如何改成不一样的呢?
name$ sudo chown root.root bin/process_id
[sudo] password for user:  //输入超级用户密码
name$ ls -l bin/process_id
-rwxr-xr-x 1 root root 7408 Apr 13 13:41 bin/process_id
name$ sudo chmod u+s bin/process_id
name$ ls -l bin/process_id
-rwsr-xr-x 1 root root 7408 Apr 13 13:41 bin/process_id

//euid有效用户id变成0了,实际用户id还是7588469
name$ bin/process_id
pid: 665757
ppid: 665019
uid: 7588469
euid: 0
user gid: 64000
gid: 665757
pgid: 665757
ppgid: 665019

name$ id root                    
uid=0(root) gid=0(root) groups=0(root)

8.进程创建与继承

8.1 进程创建
#include<sys/types.h>
#include<unistd.h>

pid_t fork(void);
//返回:子进程中为0,父进程中为子进程ID,出错为-1
pid_t vfork(void);
//返回:子进程中为0,父进程中为子进程ID,出错为-1
  • fork创建的新进程被称为子进程,该函数被调用一次,但返回两次。两次返回的区别是:在子进程中的返回值为0,而在父进程中的返回值则是新子进程的进程ID。
  • 创建子进程,父子进程哪个先运行根据系统调度且复制父进程的内存空间。
  • vfork创建子进程,但子进程先运行且不重复父进程的内存空间。

例一:单次运行父进程和子进程

name$ vim src/process_fork.c
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    printf("pid: %d\n", getpid());

    pid_t pid;
    pid =fork(); //create child process
    //After fork, there are two processes, namely the p
arent process and the child process
    if (pid < 0) {
         perror("fork error");
    }else if (pid > 0) {
        //parent process
        printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
    }else {
        //child process
        printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
    }

    printf("pid: %d\n", getpid());

    sleep(1);

    exit(0);
}

name$ gcc -o bin/process_fork src/process_fork                                              
name$ bin/process_fork
pid: 704017
I am parent process pid is 704017, ppid is 665019, fork return is 704018
pid: 704017
I am child process pid is 704018, ppid is 704017, fork return is 0
pid: 704018 

name$ ps
   PID TTY          TIME CMD
665019 pts/60   00:00:00 bash
709057 pts/60   00:00:00 ps

例二:多次交替执行父子进程(父子进程运行顺序不一定,根绝实际系统调用情况来决定)

name$ vim src/process_fork2.c                                                               
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>

int main(void)
{
    printf("current pid: %d\n", getpid());

    pid_t pid = fork();
    if(pid < 0){
         perror("fork error");
    }else if(pid > 0){ //parent process
        int i;
        for(i = 0; i < 10; i++){
            printf("This is parent process pid is: %d\n", getpid());
            sleep(1);
        }
    }else{ //child process
        int i;
        for(i = 0; i < 10; i++){
            printf("This is child process pid is: %d\n", getpid());
            sleep(1);
        }
    }

    return 0;
}

name$ gcc -o bin/process_fork2 src/process_fork2.c                                                      
name$ bin/process_fork2                           
current pid: 33140
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
This is parent process pid is: 33140
This is child process pid is: 33141
8.2 继承

父进程fork出子进程,子进程会继承父进程的一些信息

8.2.1 子进程的继承属性
  • 用户信息和权限、目录信息、信号信息、环境、共享存储段、资源限制、堆、栈和数据段、共享代码段。(父子进程的物理内存空间是不一样的)

注:P1代表父进程,P2代表子进程。

例一:(全局变量和静态变量存放在数据段,局部变量存放在栈中)

name$ vim src/process_fork.c
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>

int g_v = 30;

int main(void)
{
    int a_v = 30;
    static int s_v = 30;

    printf("pid: %d\n", getpid());

    pid_t pid;
    pid =fork(); //create child process
    //After fork, there are two processes, namely the parent process and the child process
    if (pid < 0) {
         perror("fork error");
    }else if (pid > 0) {
        //parent process
        g_v = 40; a_v = 40; s_v = 40;
        printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
        printf("g_v: %p, a_v:%p, s_v: %p\n", &g_v, &a_v, &s_v);
    }else {
        //child process
        g_v = 50; a_v = 50; s_v = 50;
        printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
        printf("g_v: %p, a_v:%p, s_v: %p\n", &g_v, &a_v, &s_v);
    }

    printf("pid: %d, g_v:%d, a_v:%d, s_v:%d\n", getpid(), g_v, a_v, s_v);

    sleep(1);

    exit(0);
}

user$ gcc -o bin/process_fork src/process_fork.c 
user$ bin/process_fork
pid: 68503
I am parent process pid is 68503, ppid is 61863, fork return is 68504
g_v: 0x601064, a_v:0x7ffee4891708, s_v: 0x601068
pid: 68503, g_v:40, a_v:40, s_v:40
I am child process pid is 68504, ppid is 68503, fork return is 0
g_v: 0x601064, a_v:0x7ffee4891708, s_v: 0x601068
pid: 68504, g_v:50, a_v:50, s_v:50

缓存数据在堆里

name$ vim src/process_fork.c
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>

int g_v = 30;

int main(void)
{
    int a_v = 30;
    static int s_v = 30;
    printf("pid: %d\n", getpid());

    FILE *fp = fopen("s.txt", "W");
    int fd = open("s_fd.txt",
                   O_WRONLY|O_CREAT|O_TRUNC,
                   S_IRWXU|S_IRWXG);
    char *s = "hello iotek";
    ssize_t size = strlen(s) * sizeof(char);

    //父进程调用
    //标准I/O函数(带缓存-->全缓存)
    fprintf(fp, "s:%s, pid:%d", s, getpid()); //写入缓存
    //内核提供的I/O系统调用(不带缓存)
    write(fd, s, size); //直接写入文件

    pid_t pid;
    pid =fork(); //create child process
    //After fork, there are two processes, namely the parent process and the child process
    if (pid < 0) {
         perror("fork error");
    }else if (pid > 0) {
        //parent process
        g_v = 40; a_v = 40; s_v = 40;
        printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
        printf("g_v: %p, a_v:%p, s_v: %p\n", &g_v, &a_v, &s_v);
    }else {
        //child process
        g_v = 50; a_v = 50; s_v = 50;
        printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
                getpid(), getppid(), pid);
        printf("g_v: %p, a_v:%p, s_v: %p\n", &g_v, &a_v, &s_v);
    }

    //printf("pid: %d, g_v:%d, a_v:%d, s_v:%d\n", getpid(), g_v, a_v, s_v);
    //父子进程都要执行,写入缓存
    fprintf(fp, "pid: %d, g_v:%d, a_v:%d, s_v:%d\n", getpid(), g_v, a_v, s_v);

    sleep(1);
    
    fclose(fp);
    close(fd);

    exit(0);
}

name$ gcc -o bin/process_fork src/process_fork.c 
name$ bin/process_fork                       
pid: 68503
I am parent process pid is 68503, ppid is 61863, fork return is 68504
g_v: 0x601064, a_v:0x7ffee4891708, s_v: 0x601068
I am child process pid is 68504, ppid is 68503, fork return is 0
g_v: 0x601064, a_v:0x7ffee4891708, s_v: 0x601068

name$ more s_fd.txt
hello iotek
name$ more s.txt
s:hello iotek, pid: 68503 pid: 68503, g_v:40, a_v:40, s_v:40
s:hello iotek, pid: 68503 pid: 68504, g_v:50, a_v:50, s_v:50
8.2.2 子进程特有属性
  • 进程ID、锁信息、运行时间、未决信号
8.2.3 操作文件时的内核结构变化
  • 子进程只继承父进程的文件描述表,不继承但共享文件表项和i-node。
  • 父进程创建一个子进程后,文件表项中的引用计数器加1变成2,当父进程作close操作后,计数器减1,子进程还是可以使用文件表项,只有计数器为0时才会释放文件表项。
name$ vim src/process_append.c
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])
{
    if(argc < 2){
        fprintf(stderr, "usage: %s file\n",argv[0]);
        exit(1);
    }

    int fd = open(argv[1], O_WRONLY);
    if(fd < 2){
        perror("open error");
        exit(1);
    }

    pid_t pid = fork();
    if(pid < 0){
        perror("fork error");
        exit(1);
    }else if(pid > 0){//parent process
        //父进程将文件偏移量调整到文件尾部
        if(lseek(fd, 0L, SEEK_END) < 0){
            perror("lseek error");
            exit(1);
        }
    }else{//child process
        //子进程从文件尾部追加内容
        char *str = "\nhello child";
        ssize_t size = strlen(str) * sizeof(char);
        sleep(3);

        //此处的fd是从父进程中复制过来的,但是和父进程中的fd都是指向同一个文件
        if(write(fd, str, size) != size){
            perror("write error");
            exit(1);
        }
    }

    printf("pid: %d finish\n", getpid());
    sleep(1);

    //父子进程都要去关闭文件描述符表
    close(fd);

    return 0;
}

name$ gcc -o bin/process_append src/process_append.c
name$ more s_fd.txt 
hello 
name$ bin/process_append s_fd.txt 
pid: 642694 finish
name$ pid: 642695 finish 

name$ more s_fd.txt              
hello 
hello child

9.进程链、进程扇

  • 进程链:父进程只fork一个子进程,而子进程继续创建子进程,子进程变父进程后不能再创建子进程。简言之:创建进程后,判断父进程退出循环,子进程继续循环
  • 进程扇:与进程链反过来,父进程创建多个子进程,而子进程不再创建子进程。简言之:判断子进程退出循环,父进程继续循环fork

例一:进程链

name$ vim src/process_link.c  
//进程链    
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])
{
    int counter = 0;
    if(argc < 2)
        counter = 2;
    else
        counter = atoi(argv[1]);

    int i = 1;
    pid_t pid;
    for(; i < counter; i++){
        pid = fork();
        if(pid < 0){
            perror("fork error");
            exit(1);
        }else if(pid > 0) break;
        //如果是父进程,退出,子进程会继续创建子进程
    }

    printf("pid: %d, ppid: %d\n", getpid(), getppid());
    sleep(2);

    return 0;
}

name$ gcc -o bin/process_link src/process_link.c 
name$ bin/process_link            
pid: 665967, ppid: 316581
pid: 665968, ppid: 665967
name$ ps                          
   PID TTY          TIME CMD
316581 pts/1    00:00:00 bash
665993 pts/1    00:00:00 ps
name$ bin/process_link 5
pid: 668736, ppid: 316581
pid: 668737, ppid: 668736
pid: 668738, ppid: 668737
pid: 668739, ppid: 668738
pid: 668740, ppid: 668739

例二:进程扇

name$ cp src/process_link.c src/process_swing.c
name$ vim src/process_swing.c 
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])
{
    int counter = 0;
    if(argc < 2)
        counter = 2;
    else
        counter = atoi(argv[1]);

    int i = 1;
    pid_t pid;
    for(; i < counter; i++){
        pid = fork();
        if(pid < 0){
            perror("fork error");
            exit(1);
        }else if(pid == 0) break;
        //这里做修改,如果是子进程,退出循环,父进程继续fork
    }

    printf("pid: %d, ppid: %d\n", getpid(), getppid());
    sleep(2);

    return 0;
}
name$ gcc -o bin/process_swing src/process_swing.c 
name$ bin/process_swing 5         
pid: 671925, ppid: 671924
pid: 671926, ppid: 671924
pid: 671924, ppid: 316581
pid: 671927, ppid: 671924
pid: 671928, ppid: 671924
name$ ps                         
   PID TTY          TIME CMD
316581 pts/1    00:00:00 bash
671937 pts/1    00:00:00 ps

10.几种特殊进程

10.1 僵尸进程
10.1.1 概念:
  • 子进程结束但是没有完全释放内存(在内核中的task_struck没有释放),该进程就成为僵尸进程。<defunct>
  • 当僵尸进程的父进程结束后就会被init进程领养,最终被回收。
name$ vim src/process_zombie.c 
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>

int main(void)
{
    pid_t pid;
    pid = fork();
    if(pid < 0){
        perror("fork error");
        exit(1);
    }else if(pid == 0){ //child process
        printf("pid: %d, ppid: %d\n", getpid(), ge
tppid());
        exit(0); //子进程结束成为僵尸进程
    }
    while(1){ //父进程继续循环
        sleep(1);
    }

    return 0;
}

name$ gcc -o bin/process_zombie src/process_zombie.c 
name$ bin/process_zombie     //目前父进程被挂住了,执行ctrl + C可以中断等待,结束父进程。
pid: 128065, ppid: 128064

//打开另一个窗口查看进程状态
name$ ps -aux | grep process_zombie
name  128064  0.0  0.0   4216   360 pts/37   S+   16:48   0:00 bin/process_zombie
name  128065  0.0  0.0      0     0 pts/37   Z+   16:48   0:00 [process_zombie]<defunct>
name  130951  0.0  0.0 112812   948 pts/39   S+   16:50   0:00 grep --color= autoprocess_zombie  
10.1.2 如何避免僵尸进程
  • 让僵尸进程的父进程来回收,父进程每隔一段时间来查询子进程是否结束并挥手,调用wait()或者waitpid(),通知内核释放僵尸进程。
  • 采用信号SIGCHILD通知处理,并在信号处理程序中调用wait函数。
  • 让僵尸进程成为孤儿进程,由init进程回收。
10.2 守护进程
  • 守护进程是生长周期长的一种进程。他们常常在系统引导装入是启动,在系统关闭时终止。
  • 所有守护进程都以超级用户(用户ID为0)的优先权运行
  • 守护进程没有控制终端
  • 守护进程的父进程都是init进程
10.3 孤儿进程
  • 父进程结束,子进程就会成为孤儿进程,会由1号进程(init进程)领养。
name$ vim src/process_orphen.c
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    pid_t pid;
    pid = fork();
    if(pid < 0){
        perror("fork error");
        exit(1);
    }else if(pid > 0){//parent process
        printf("%d deaded\n", getpid());
        exit(0);
    }else{ //child process
        sleep(4);
        printf("pid: %d, ppid: %d\n", getpid(),get
ppid());
    } 

    return 0;
}

name$ gcc -o bin/process_orphen src/process_orphen.c 
name$ bin/process_orphen   
158033 deaded
name$ pid: 158034, ppid: 1   

  • 26
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值