• Unix环境_进程管理


    一、基本概念
      1、进程与程序
      程序是存储在磁盘上的文件,它是包含要执行的机器指令和数据的静态实体。
      进程是一个正在运行的程序,一个程序可能包含多个进程(多任务、多进程),进程在操作系统中是一个执行任务的单位。

      2、进程的分类
      交互进程:需要用户输入数据,也会显示一些结果给用户看。
      批处理进程:用来执行脚本的进程,例如Makefile。
      守护进程:它是一种一直活跃的进程,一般是后台的,由操作系统启动时通过开过开机脚本加载或由超级用户加载。

      3、查看进程
      ps:显示当用户当前终端所控制的进程。
      -a:显示所有用户的进程
      -x:包括无终端控制的进程
      -u:显示详细信息
      -w:以更宽的方式显示

    USER:属主  PID:进程号  %CPU:cpu占用率  %MEM:内存使用率  VSZ:虚拟内存的大小
    RSS:物理内存的使用量  TTY:终端设备号,如果不是终端控制进程用'?'表示  STAT:终端的状态
    START:开始时间  TIME:运行时间  COMMAND:开启此进程的命令
      
      4、进程的状态
      O:就绪态,一切准备工作都已经做好,等待被调用。
      R:运行态,Linux下没有就绪态,O也就是R。
      S:可唤醒的睡眠态,系统调用、获取到资源、收到信息都可以被唤醒。
      D:不可唤醒的睡眠态,必须等到的事件发生。
      T:暂停态,收到了SIGSTOP信号,当收到SIGCONT信号则继续运行。
      X:死亡态。
      Z:僵尸态。
      <:高优先级。
      N:低优先级。
      L:多线程进程。
      s:有子进程的进程。
      +:后台进程组。

      5、父子进程
      如果进程B是由进程A开启的,那么我们把进程A叫进程B的父进程,进程B叫作进程A的子进程。
      当子进程结束后会向父进程发送,SIGCHLD,父进程收到信号后再回收子进程。
      当先父进程先结束,子进程就会变成孤儿进程,会被孤儿院(init)收养。
      如果子进程已经结束,但父进程没有及时回收,子进程就变成了僵尸进程。

      6、进程标识符,
      俗称进程号,它是一个无符号整数,使用getpid函数可以获取到。
      这种编号是循环使用,当进程结束后,它就跟这个编号没有关系,这个编号也会被再次使用,即延时重用。
      
    二、getxxid
    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

    三、fork
    pid_t fork(void);
    功能:创建子进程

    1、失败返回-1,如果成功会返回两次。
    2、父进程会返回子进程的id,子进程返回0
    3、根据返回值的不同,分别为子进程和父进程设计不同的分支。
    4、通过fork创建出的子进程,就是父进程的副本,它会把父进程的堆、栈、全局段、静态数据段、IO流的缓冲区都拷贝一份,父子进程共享代码段。
    5、fork函数调用成功后,父子进程就开始各自执行了,它们的先后顺序是不确定的,但可以通过某些实现来保证。
    6、当总进程数超过系统的限制时,就无法再创建进程的了,此时fork函数会返回-1,执行失败。
    7、孤儿进程:子进程还有运行,但父进程已经结束,此时子进程会被init(1)收养,子进程变成孤儿进程。
    8、僵尸进程:子进程已经死亡,但父进程没有及时回收子进程,此时子进程就会变成僵尸进程。
    9、父进程打开的文件和子进程是共享的。
    注意:fork之前的代码,只有父进程在执行,fork之后的代码父子进程都有机会执行,根据fork返回值来控制进入不同的分支。

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
        int pid = fork();
        if(0 == pid)
        {
               
            printf("进程id:%d 父进程id:%d
    ",
                getpid(),getppid());
            
        }
        sleep(1);
        printf("进程id:%d 子进程id:%d
    ",
            getpid(),pid);
    }

    执行结果为: 

     

    四、vfork,execl
    pid_t vfork(void);
    功能:创建子进程

    1、vfork不能单独创建子进程,需要与excl函数簇,配合才完成子进程的创建。
    2、它不会复制父进程的栈、堆、数据、全局等段,也不会共享代码段,而是通过excl函数调用一个程序直接启动,从面提高创建进程的效率。
    3、使用vfork创建的子进程保证,先执行子进程,后执行父进程。

    execl函数

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

    path:可执行文件的路径
    arg:给可执行文件的参数,类似于命令行参数,必须以NULL结尾,第一个必须是可以执行文件名。
    execl("","a.out",NULL);

    五、进程的正常退出
    1、从main退出,在main中执行return 0;

    返回值的低8位会被父进程获取到。
    使用_exit/_Exit退出前会关闭所有打开的文件流,如果有子进程则会托附给init,然后向父进程发送SIGCHLD信号。
    此函数不会返回。

    2、调用标准C的exit(stat)函数

    exit在底层实现上调用了_exit/_Exit函数,所以_exit/_Exit的特点它都具备。
    exit结束前会调用通过atexit/on_exit注册的函数。

    int atexit(void (*function)(void));
    int on_exit(void (*function)(int , void *), void *arg);

    3、最后一个线程正常结束

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void exit_func(int stats,void * str)
    {
        printf("我是以%d的状态结束的,我最后遗言是:%s
    ",stats,str);
    }
    
    int main()
    {
        on_exit(exit_func,"我走了");
        for(int i=0; i<5; i++)
        {
            sleep(1);
            printf("%d
    ",i++);
        }
        exit(110);
        return 1;
    }

    程序执行结果为:


    六、进程异常中止
    1、进程调用了abort函数(段错误、浮点异常)
    2、进程接收到某些信号
    crtl+c  crtl+  ctrl+z
    3、最后一个线程收到取消操作,而且线程作出响应。

    七、子进程的回收

    pid_t wait(int *status);
    功能:等待子进程结束,并回收

    pid_t waitpid(pid_t pid, int *status,int options);
    功能:等待指定的子进程结束,并回收

    1、父进程调用wait

    如果所有的子进程都在运行,则父进程阻塞(wait),只要有一个子进程结束了,会立即返回子进程的id和结束状态
    当所有子进程都结束运行时,wait会返回-1。当不需要子进程的结束状态时,status的值可为NULL,可利用 while(-1 != wait(NULL)) 回收所有子进程。

    2、waitpid函数可以指定等待哪个子进程结束
    pid:指定的pid
      == -1 功能与wait类似,pid就无意义了。
      > 0 等待进程号是pid的进程结束。
      == 0 等待与父进程同组的字进程结束。
      < -1 等待组id是pid的绝对值的进程组中任意进程结束。

    status:用于接收子进程的结束状态,如果不需要状态码可以设置为NULL;

    options:
    0 以阻塞状态等待子进程结束
    WNOHANG 如果没有子进程退出会立即返回。
    WUNTRACED 等待的进程处于停止状态,并且之前没有报告过,则立即返回。

    3、如果不调用wait/waitpid函数,子进程结束后就处于僵尸状态,当父进程也结束时,父进程的父进程会把他们统一回收。


  • 相关阅读:
    树链剖分总结
    主席树总结
    BZOJ1053:反素数(数学)
    CH3101 阶乘分解
    2018-2019 ACM-ICPC ECfinal I. Misunderstood … Missing
    洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
    Codeforces Round #552 (Div. 3) 题解
    线段树合并 总结
    生成器
    Python中input()和raw_input()的区别
  • 原文地址:https://www.cnblogs.com/xiehuan-blog/p/9392667.html
Copyright © 2020-2023  润新知