3

Linux进程相关 创建与回收

 2 years ago
source link: https://blog.csdn.net/qq_43900551/article/details/120168472
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
  • 掌握fork/getpid/getpid/getppid函数的使用
  • 熟练掌握ps/kill命令的使用
  • 熟练掌握execl/execlp函数的使用
  • 说出什么时僵尸进程 什么是孤儿进程
  • 熟练掌握wait函数的使用
  • 熟练掌握waitpid函数的使用

程序相关概念

什么是程序 ?

编译好的二进制文件 .

什么是进程 ?

运行着的程序. 站在程序员的角度,运行一系列指令的过程. 站在系统角度分配好资源的基本单位.

区别

  • 程序占用磁盘,不占用系统资源

  • 内存占用系统资源

  • 一个程序对应多个进程,一个进程对应一个程序.

  • 程序没有生命周期,进程有生命周期.

进程相关函数

fork 创建进程

#include <unistd.h>

pid_t fork(void);

返回值

  • 失败返回-1

  • 成功两次返回

    • 父亲进程返回 子进程id
    • 子进程返回0

getpid获取进程id / getppid获取父进程id

#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);		
pid_t getppid(void);
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>

int main()
{
    pid_t id = getpid();

    printf("当前进程的id为:%d\n",id);

    printf("开始创建进程\n");
    pid_t id1 = fork();
    if(id1<0){
        perror("fork err");
        return -1;
    }
    printf("\n创建进程结束\n");
    if(id1 == 0)
    {
        
        printf("我是子进程:%d\n",getpid());
        pid_t id2 = getppid();
        printf("我的父进程:%d\n",id2);
        return 0;
    }
    
    printf("我是父进程:%d\n",id);
    printf("我的子进程:%d\n",id1);


    return 0;
}

子进程打印时发现父进程的id为1 因为父进程先死了.

ps aux

ps ajx

kill -9 进程id

父子进程之间在fork后.有哪些相同不同之处?

刚fork后:

  • 父子相同之处:全局变量, data, text, 堆, 栈, 环境变量, 用户id, 宿主目录, 进程工作目录, 信号处理函数…
  • 父子不同之处:
    1. fork() 返回值
    2. 进程运行时间
    3. 闹钟(定时器)
    4. 未决信号集

似乎子进程复制了父进程0-3G的用户空间, 以及父进程的PCB, 但pid不同. 真的每一个子进程都复制了一份父进程的地址空间?

当然不是, 父子进程遵循读时共享,写时复制的原则. 这样无论执行子进程还是父进程的逻辑都能节省空间开销.

测试,父子进程是否共享变量.

#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>

int main()
{
    int a = 100;
    pid_t pid  = fork();
    if(pid < 0)
    {
        printf("创建子进程失败\n");
        return 0;
    }
    if(pid == 0)
    {
        printf("子进程a 的地址%p\n",&a);
    }
    else
    {
        printf("父进程a 的地址%p\n",&a);
        sleep(1);
    }

}

exec族函数

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);

实例

#include<unistd.h>

int main()
{
    // execl("ls","ls","-l","--color=auto",NULL);
    execlp("/bin/ls","ls","-l","--color=auto",NULL);
    perror("");
    return 0;
}

孤儿进程和僵尸进程

孤儿进程: 父进程死了,子进程被init进程领养.

僵尸进程: 子进程死了,父进程没有回收资源(PCB)

如何回收僵尸进程: 杀死父亲,init 进程领养,负责回收.

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);

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

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

作用: 阻塞等待 回收子进程资源 查看死亡原因

wait

  • 成功返回终止的子进程ID
  • 失败返回-1

waitpid

  • pid
    • <-1 -组id
    • -1 回收任意
    • 0 回收和调用进程id相同组内的子进程
    • >0 回收指定的pid
  • options
    • 0与wait相同,也会阻塞
    • WNOHANG 如果当前没有子进程退出,会立刻返回

查看死亡原因

  • 正常死亡: WIFEXITED(status)

    如果正常死亡 WIFEXITED为真,WEXITSTATUS(status)得到退出状态

  • 非正常死亡 WIFSIGNALED(status)

    WIFSIGNALED为真WTERMSIG(status)得到第几号信号将其杀死的.

#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        printf("I am child, will die!\n");
        sleep(2);
        // return 102;
        exit(103);
    }
    else if(pid >0)
    {
        printf("I am parent, wait for child die\n");
        int status;

        pid_t wpid = wait(&status);
        printf("wait ok, wpid = %d, pid = %d\n",wpid,pid);
        if(WIFEXITED(status)){
            printf("child exit with %d\n",WEXITSTATUS(status));
        }
        if(WIFSIGNALED(status)){
            printf("child exit with %d\n",WTERMSIG(status));
        }
    }

    return 0;
}


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK