• [操作系统自由练习] 进程的创建, fork()函数



    author: 泥烟


    ps命令查看系统进程

    ps 的参数很多, 在此仅列出几个常用的参数

    • -A 列出所有的进程

    • -w 显示加宽可以显示较多的资讯

    • -ef 显示所有命令,连带命令行

    • -au 显示较详细的资讯

    • -aux 显示所有包含其他使用者的行程

    • au(x) 输出格式 :USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

      • USER: 行程拥有者

      • %CPU: 占用的 CPU 使用率

      • %MEM: 占用的记忆体使用率

      • VSZ: 占用的虚拟记忆体大小

      • RSS: 占用的记忆体大小

      • TTY: 终端的次要装置号码 (minor device number of tty)

      • STAT: 该行程的状态

        1. D: 无法中断的休眠状态 (通常 IO 的进程)
        2. R: 正在执行中
        3. S: 静止状态
        4. T: 暂停执行
        5. Z: 不存在但暂时无法消除
        6. W: 没有足够的记忆体分页可分配
        7. <: 高优先序的行程
        8. N: 低优先序的行程
        9. L: 有记忆体分页分配并锁在记忆体内 (实时系统或捱A I/O)
    • kill -9 pid 杀死pid号的进程

      kill 发送一个特定的信号 (signal) 给 pid 的进程根据该信号而做特定的动作,若没有指定,预设是送出终止 (TERM) 的信号

    • env 查看环境变量

    在这里插入图片描述

    可以发现,

    1. 所谓的父进程(37002)是由(36841, 即程序开始执行时所创建的进程)创建的

    2. 子进程(37003)占用的虚拟内存的大小是和父进程(37002)一样的

    3. 该程序中, 尽管父进程睡两秒,子进程睡一秒, 但运行时出现了连着输出了三次子进程的情况, 我觉得应该是异步性导致的

      在这里插入图片描述

    fork1.c

    #include<stdio.h>
    #include<unistd.h>
    
    main()
    {
        int pid=fork();
        if(pid == -1){
            printf("fork failed.\n");
            return ;
        }
        else if(pid > 0) printf("%d %d\n", pid, getpid());
        else printf("%d %d\n", pid, getpid());
        printf("child\n");
        printf("father\n");
        return;
    }
    

    在这里插入图片描述

    总结

    成功创建子进程,

    父进程(47428)中pid这个变量(注意,不是父进程本身的pid)即fork后返回的值, 等于子进程的pid

    子进程(47429)中pid这个变量为0

    父子进程均输出 child father

    fork2.c

    #include <stdio.h>
    #include <errno.h>
    #include <unistd.h>
    
    main(int argc, char **argv)
    {
        int pid = fork();
        
        if(pid == 0){
            printf("Child\n");
            execl("/bin/ls", "ls", 0);
            perror("exce error!\n");
            printf("ccc");
        }
        else if(pid > 0) printf("Parent\n");
        else printf("FORK FAIL!\n");
    
        printf("%d END.\n", getpid());
    }
    
    

    在这里插入图片描述

    总结

    成功创建子进程后,

    • 子进程 >>>“child” 执行ls 结束

    • 父进程(pid=47230) >>>“Parent” >>>“END” 结束

    fork2plus.c (可传参)

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    main(int argc, char **argv)
    {
        int pid = fork();
        int rtn;
        if(pid == 0){
            printf("Child\n");
            printf("argc=%d\n", argc);
            for(int i = 1; i < argc; i ++){
                printf("执行%s...\n", argv[i]);
                system(argv[i]);
                perror(argv[i]);
            }
            exit(errno);
        }
        else if(pid > 0){
            wait(&rtn);
            printf("Chird is over, here is parent(%d)\n", getpid());
        }
        else printf("FORK FAIL!\n");
    
        printf("%d END.\n", getpid());
    }
    
    

    在这里插入图片描述

    总结

    1.分析

    流程与上面几个例子差不多,

    利用argc argv, 实现向程序内传参

    值得一提的是, 我在这里加了个wait, 等待子进程的结束

    2.argc argv

    百度百科

    argc,argv 用命令行编译程序时有用。

    主函数main中变量(int argc,char *argv[ ])的含义

    有些编译器允许将 main() 的返回类型声明为void,这已不再是合法的C++

    main(int argc, char *argv[ ], char **env)才是UNIX和Linux中的标准写法。

    argc: 整数,用来统计你运行程序时送给main函数的命令行参数的个数

    * argv[ ]: 指针数组,用来存放指向你的字符串参数的指针,每一个元素指向一个参数

    argv[0] 指向程序运行的全路径名

    argv[1] 指向在DOS命令行中执行程序名后的第一个字符串

    argv[2] 指向执行程序名后的第二个字符串

    argv[argc]为NULL。

    **env:字符串数组。env[ ]的每一个元素都包含ENVVAR=value形式的字符

    串。其中ENVVAR为环境变量,value 为ENVVAR的对应值。

    argc, argv,env是在main( )函数之前被赋值的,编译器生成的可执行文件,main( )不是真正的入口点,而是一个标准的函数,这个函数名与具体的操作系统有关。

    proc1.c

    //进程操作
    #include <unistd.h>
    #include <sys/types.h>
    #include <stdio.h>
    #include <errno.h>
    int main(int argc,char **argv)
    {
        pid_t pid,old_ppid,new_ppid;
        pid_t child,parent;
        parent = getpid();  //获得本进程PID
        if((child=fork()) < 0){
            fprintf(stderr, "%s:fork of child failed:%s\n", argv[0], strerror(errno));
            exit(1);
        }
        else if(child == 0){  //子进程被调度运行
            old_ppid = getppid();
            sleep(2);
            new_ppid = getppid();
        }
        else {
            sleep(2);
            printf("父亲(pid=%d)醒了并say good bye!\n", getpid());
            exit(0);          //父进程退出
        }
       //下面仅子进程运行
        printf("Original parent:%d\n", parent);
        printf("Child:%d\n", getpid());
        printf("Child's old ppid:%d\n", old_ppid);
        printf("Child's new ppid:%d\n", new_ppid);
        exit(0);
    }
    

    在这里插入图片描述

    总结

    这里old pid 和new pid都是指子进程47489,

    父进程睡完就溜了, 不会执行下面的输出操作

  • 相关阅读:
    XML学习笔记(七)Schema语法杂项
    UML和模式应用第一部分:绪论
    XML学习笔记(六)Schema语法之复杂类型
    XML学习笔记(四)Schema介绍篇
    XML学习笔记(三)进阶篇
    Xml学习笔记(二)Javascript篇
    AutoItLibrary安装报错(robotframework)解决
    robot framework 上个用例的输出作为下个用例的输入 (Set Global Variable的用法)
    robot framework ——关键字run keyword if 如何在一个条件下接多个执行语句,以及如何写复杂条件句
    robot framework 如何获取隐藏元素的文本,以及可见元素的文本
  • 原文地址:https://www.cnblogs.com/Knight02/p/16255359.html
Copyright © 2020-2023  润新知