• APUE学习笔记——8.1-8.4 进程基础


    进程ID

    1 进程id是唯一的。(不会有进程id一样的两个进程)

    2进程id是可复用的,一个进程销毁后,它的id号可以被新的进程使用。但是Unix采用了延迟复用的算法,也就是进程   销毁后它的id不会立即被使用。

    3 进程id为0的是调度进程。这是系统进程,是内核的一部分。

    4 进程id为1的是init进程。init进程读取初始化文件/etc/rc*files 或者/etc/inittab,以及在/etc/init.d中的文件,使系统处于      某种状态。 init进程是用户进程,而不是系统进程。


    进程id相关函数

    1. #include <unistd.h>  
    2. pid_t getpid(void);  
    3.                 Returns: process ID of calling process  
    4. pid_t getppid(void);  
    5.                 Returns: parent process ID of calling process  
    6. uid_t getuid(void);  
    7.                 Returns: real user ID of calling process  
    8. uid_t geteuid(void);  
    9.                 Returns: effective user ID of calling process  
    10. gid_t getgid(void);  
    11.                   Returns: real group ID of calling process  
    12. gid_t getegid(void);  
    13.                 Returns: effective group ID of calling process  

    创建新进程

    #include <unistd.h>
    pid_t fork(void);
                        Returns: 0 in child, process ID of child in parent,−1 on error
    Unix可以使用系统函数fork()创建一个新进程。
        fork()执行一次返回两次。
        返回值:
            0:            表示子进程
            子进程id: 表示父进程
         子进程可以通过getppid()来获取父进程id,所以只需要返回0,表示创建成功即可.而对于父进程来说,他无从得知子进程的id,因此在创建的时候就应该吧子进程的Id号返回给他。

        我们知道,每个进程都会涉及到进程控制块、正文段、数据段,三部分内容。
        进程控制块是每个进程独有的,这就不用多说。 
        正文段里面是程序的指令,都是只读的,因此父进程和子进程可以共享这部分内容 。share
        数据段:  子进程会拷贝一份父进程的数据段(数据空间、堆、栈)。注意:这里是copy而不是share

        由于我们知道,一般创建子进程后,进阶着就是使用exec替换子进程为一个新的程序了,这是父进程的数据段内容就没什么用了。因此,现代系统在实现的时候,采用了写时复制copy-on-write(COW)。该方法就是内核将数据段设置为共享share,但它是只读的,当父进程或者子进程下需要对数据进行修改时,就自己copy一个副本。

        Example
    #include "apue.h"
    #include "myerr.h"
    int  globvar=6;/*external variable in initialized data */
    char  buf[] = "a write to stdout
    ";
    int
    main(void)
    {
            int  var; /* automatic variable on the stack */
            pid_t  pid;
            var = 88;
            if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
                    err_sys("write error");
            printf("before fork
    "); /* we don’t flush stdout */
            if ((pid = fork()) < 0) {
                    err_sys("fork error");
            }else if (pid == 0) { /* child */
                    globvar++;  /* modify variables */
                    var++;
            }else {
                    sleep(2);  /* parent */
            }
            printf("pid = %ld, glob = %d, var = %d
    ", (long)getpid(), globvar, var);
            exit(0);
    }
    执行结果:
    windeal@ubuntu:~/Windeal/apue$ ./exe 
    a write to stdout
    before fork
    pid = 4523, glob = 7, var = 89
    pid = 4522, glob = 6, var = 88
    windeal@ubuntu:~/Windeal/apue$ 

    在这个例子中,我们在子进程中对globvar和var都进行自加,然后又在父进程中sleep(2),使得子进程先执行。
    最终结果,父进程的数据都没变,子进程globvar和var都变成了新的值。
        从例子中可以看出,正文段是共享的,都使用了printf语句(你要说是copy,我就不跟你辩了。。。)
    vfork()
        功能与fork()基本相似。
        不同点:
            vfork保证子进程先执行,也就是子进程执行了exec程序或者exit后才执行fork()。如果子进程中有依赖父进程的下一步动作才能执行的部分,可能会导致死锁。
            vfork创建的子进程会共享父进程的数据段。也就是说它会改变父进程的数据。
    #include "apue.h"
    #include "myerr.h"
    int  globvar=6;/*external variable in initialized data */
    int
    main(void)
    {
            int  var; /* automatic variable on the stack */
            pid_t  pid;
            var = 88;
            printf("before vfork
    "); /* we don’t flush stdio */
            if ((pid = vfork()) < 0) {
                    err_sys("vfork error");
            }else if  (pid == 0) { /* child */
                    globvar++;  /* modify parent’s variables */
                    var++;
                    _exit(0);  /* child terminates */
            }
            /* parent continues here */
            printf("pid = %ld, glob = %d, var = %d
    ", (long)getpid(), globvar, var);
            exit(0);
    }


    执行结果:
    windeal@ubuntu:~/Windeal/apue$ ./exe 
    before vfork
    pid = 6298, glob = 7, var = 89
    windeal@ubuntu:~/Windeal/apue$


    可以看到父进程globvar和var被子进程改变了。

            vfork()被一些版本视为过时的接口,一般不使用。所以不必过多研究,多用fork()来创建新进程即可。


  • 相关阅读:
    JavaScript 将数组中具有相同值的对象 取出组成新的数组
    css样式初始化
    javaScript如何跳出多重循环break、continue
    vue-cli中webpack配置解析
    Invalid prop: type check failed for prop "XXX". Expected String, got Object.
    vue-cli构建项目添加网站ico的logo
    vue-cli构建的vue项目打包后css引入的背景图路径不对的问题
    从零开始使用vue-cli搭建一个vue项目及注意事项
    安装npm及cnpm(Windows)
    面试题8:旋转数组中的最小数字
  • 原文地址:https://www.cnblogs.com/Windeal/p/4284651.html
Copyright © 2020-2023  润新知