• UNIX环境C语言进程控制


    一、进程ID

    进程ID即是进程标识,每一个进程都会有一个唯一的非负整数来作为它的进程ID。

    ID为0的进程通常是调度进程,也可称为交换进程,该进程是内核的一部分,不执行硬盘上的程序,因此也被称为系统进程。

    ID为1的进程通常是init进程,init通常读取与系统有关的初始化文件,,并将系统引导到一个状态。init进程绝不会终止,它是一个普通的用户进程,但是它以超级用户特权运行,init会称为所以孤儿进程的父进程。

    进程ID可以由以下函数获得

    1 #include <unistd.h>
    2 
    3 pid_t    getpid(void);                //返回值:调用进程的进程ID
    4 pid_t    getppid(void);              //返回值:调用进程的父进程ID
    5 uid_t    getuid(void);               //返回值:调用进程的实际用户ID
    6 uid_t    geteuid(void);             //返回值:调用进程的有效用户ID
    7 gid_t    getgid(void);               //返回值:调用进程的实际组ID
    8 gid_t    getegid(void);             //返回值:调用进程的有效组ID

    二、函数fork

    #include  <unistd.h>
    
    pid_t     fork(void);        //返回值:子进程返回0,父进程返回子进程的进程ID,失败返回-1

    fork函数执行成功时会返回两次,一次在父进程中返回子进程的进程ID,一次在子进程中返回0,因此可以在此使用if语句作为父子进程的分支。子进程是父进程的副本,共享的只有代码段,子进程的堆、栈、全局段、静态数据段都是父进程的副本,是在创建在子进程时拷贝的。

    fork之后父进程和子进程的执行先后是不确定的,这取决于内核所使用的调度算法。

    文件共享

    父进程和子进程之间打开的文件是共享的,原理是子进程使用了从父进程拷贝的文件标识符,使得它们可以访问同一个文件,另外,它们共享同一个文件偏移量

    三、函数vfork

    #include <unistd.h>
    
    pid_t    vfork(void) ;       //返回值:子进程返回0,父进程返回子进程的进程ID,失败返回-1

    vfork函数同样用于创建一个子进程,但是它与fork不同的是,vfok创建的新进程的目的是加载(exec)一个新程序。vfork调用后,会保证子程序的先运行,知道它调用exec或exit父程序才会被调度运行(如果子进程在此过程中需要父进程的进一步动作,会导致程序锁死)

    四、进程的终止

    进程有五种正常终止和三种异常终止方式,这里不一一阐述,主要说明以下一种。

    调用exit函数

    exit函数由ISO C定义,其操作包括调用各终止处理程序,然后关闭I/O流等

    其中终止处理程序由函数atexit和on_exit登记

    #include <stdlib.h>
    
    int atexit(void (*function)(void));   //funtion:需要进行终止处理的函数指针,返回值:成功返回0
    
    
    int on_exit(void (*function)(int stats, void * arg), void *arg);  //funtion:于atexit不同的是,该函数可得到exit的参数,即,能够知道程序是在什么状态下终止的

    五、函数wait和waitpid

    这两个函数的作用是等待子进程终止,它们的函数定义如下

    #include <sys/wait.h>
    
    
    pid_t  wait(int *statloc);
    //statloc: 用于接收子进程的结束状态 
    //返回值:子进程进程号 
    
    
    
    pid_t  waitpid(pid_t   pid, int  *statloc,  int   option);
    /* statloc:同上 
    pid:    == -1 功能与wait类似,pid就无意义了 
          == 0 等待组id等于pid的进程组中任意进程结束。 
          < -1 等待组id是pid的绝对值的任意进程结束 
          > 0 等待进程号是pid的进程结束
    
    options     0 :以阻塞状态等待子进程结束
                WNOHANG         如果没有子进程结束会立即返回
                WUNTRACED    等待的进程处于停止状态,并且之前,没有报告过,则立即返回
    返回值:子进程的进程号
    */

    在一个子进程 终止前,wait使其调用者阻塞,而waitpid可以使调用者不阻塞

    waitpid可以控制等待指定的某个子进程

    如果子进程在wait调用前就已终止,wait会立即返回并取得该子进程的状态,否则wait使调用者阻塞

    当一个进程终止时,内核就会向它的父进程发送一个SIGCHLD信号。父进程可以在信号处理函数中用wait接收到子进程的结束状态,进行一些相应操作,可以大大增加程序运行效率。

    六、函数exec

    使用fork函数或vfork能够创建新的子进程,子进程调用exec后可以执行另一个程序,新程序从main函数开始执行,因为调用exec不创建新的进程,只是将子进程替换为新的程序,所以前后进程ID并不改变

    exec函数有以下几种:

    #include <unistd.h>
    
        int execl(const char *path, const char *arg, ...);
        path:可执行文件的路径+名字
        arg:给可执行文件的参数,类似于命令行参数,必须以NULL结尾,第一个必须是可执行文件名。
    
        int execlp(const char *file, const char *arg, ...);
        file:可执行文件的文件名,会从PATH环境变量指定的位置找可执行文件
        
        int execle(const char *path, const char *arg,..., char * const envp[]);
        envp:环境变量表,父进程更改后的环境变量表
        
        int execv(const char *path, char *const argv[]);
        
        int execvp(const char *file, char *const argv[]);
        
        int execvpe(const char *file, char *const argv[],char *const envp[]);
    
        int fexecve(int fd, char *const argv[], char *const envp[]);

    七、函数fork与vfork区别

    fork函数

    使用fork函数创建的子进程,会将父进程的数据段、堆栈复制,与父进程共享代码段。

    vfork函数

    vfork函数的调用通常是为了创建新进程来exec一个新程序,vfork不会将父进程的地址空间完全复制到子进程中,vfork函数创建的子进程在调用exec和exitz之前,它会在完全运行在父进程的地址空间上,vfork会保证子程序的先运行,直到调用exec和exit之后父进程才有可能被调度运行。

    使用vfork和fork创建子进程都能够调用exec产生新的程序,然而vfork函数不会对父进程的地址空间进行复制,通过使用vfork可以减少不必要的开销
  • 相关阅读:
    关于new 这个动作怎么理解面试遇到过
    _proto_ 和prototype自己的理解
    关于原始input的一些事情
    关于promise自己的理解
    event loop事件循环机制
    详解text-overflow 与 word-wrap ---------->>>>css加省.....英文换行处理
    vue滚动事件销毁,填坑
    vue中检测敏感词,锚点
    让文字两端对齐
    中文分词系列(一) 双数组Tire树(DART)详解
  • 原文地址:https://www.cnblogs.com/unjack/p/9362096.html
Copyright © 2020-2023  润新知