第36天-进程 _1(2013.09.06)

  1.物理地址-------MMU------》虚拟地址----启动进程---->进程空间地址

  2.Uxworks  FreeRTOS  Ucos/2

  3. volatile(不优化)  register(尽量优化)

  4.每个进程在内核中都有一个进程控制块来维护相关的信息,  Linux内核的进程控制块是tast_struct结构体

  5.两个重要的系统调用 fork(刀叉, 民间的, 分叉) 和 exec(执行)

      fork的作用 :根据一个现有的进程复制出一个新进程, 原来的进程称为父进程,新的进程称为子进程

      例外 : 子进程PCB中的进程id和父进程是不同的

  6.exit 和 _exit函数用于终止一个进程

      函数原型 : #include <stdlib.h>    void exit(int status);

            #include <unistd.h>    void _exit(int status);

      区别 :exit是标准C的库函数,负责完成标准C的其他库函数留下的清理工作。

          _exit是UNIX系统函数,是exit系统调用的包装,调用_exit函数时直接进入内核终止掉当前进程,释放分配的内存,关闭文件描述符, 不需要做用户空间的清理工作。

      扩展 : exit在做完清理工作后最终也是调用_exit终止当前进程的

  7.异常终止 :进程收到一个信号,然后内核把进程强行终止掉了, 进程并么有执行 _exit系统调用,也没有退出状态。(例如: Ctrl-C 或着Kill命令终止一个进程)

  8.可以使用echo 命令查看这个环境变量的值。

  9.如果给出name要在环境变量表中查找它对应的value, 可以用getenv函数

      函数原型 : #include <stdlib.h>  char *getenv(const char *name);

      返回值 : getenv的返回值是指向value的指针, 若未找到则为NULL 

  10. 修改环境变量的函数 :

      函数原型 : int setenv(const char *name, const char *value, int rewrite);

            void unsetenv(const char *name);

      putenv 和 setenv 函数若成功返回为0, 若出错返回非0

      setenv将环境变量name的值设置为value, 如果已存在环境变量name. 那么

              若rewirite非0, 则覆盖原来的定义

              若rewrite为0, 则不覆盖原来的定义, 也不返回错误

      unsetenv 删除name的定义。 即使name么有定义也不返回错误。

  11. 可剥夺型内核和不可剥夺型内核

  12.fork函数

       函数原型 : #include <sys/types.h>  #include <unistd.h>    pid_t fork(void)

       返回值 : 调用失败返回-1. 调用成功有两个返回值(pid == 0)执行子进程,(pid > 0)执行父进程

       当父进程结束,程序直接返回。

       可以使用usleep(0)在两个进程间故意切换

       fork函数的特点 : 调用一次 , 返回两次

       注意: fork在子进程中返回0, 子进程仍可以调用getpid函数得到自己的进程id, 也可以调用getppid函数得到父进程的id。在父进程中可以用getpid函数得到自己的进程id,然而想要得到子进程的id,只有将fork的返回值记录下来, 别无它法。

       fork的另一个特性 : 所有有父进程打开的描述符都被复制到子进程中。(即file结构体的引用计数要增加)

       gdb调式: 

            set follow-fork-mode child 命令设置gdb在fork之后跟踪子进程

            set follow-fork-mode parent 跟踪父进程。 

  13.exec函数  (Executive)执行

      提示: 调用exec前后該进程的id并未改变

      函数原型: #include <unistd.h>

          (重点)int execvp(const char *file, char *const argv[]);

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

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

              int execle(const char *path, const char *arg, ..., char *const envp[]);

              int execv(const char *path, char *const argv[]);

              int execve(const char *path, char *const argv[], char *const envp[]);

      补充: 最少有两个指针, argv最后一个为 NULL

      扩展 : exec函数只有出错的返回值而没有成功的返回值,,出错返回-1

  14.僵尸进程: 如果一个进程已经终止, 但是它的父进程尚未调用wait或waitpid对它进行清理, 这时的状态称为僵尸进程

  15.如果一个父进程终止,而它的子进程还存在,则这些子进程的父进程改为init进程

        init进程: 一个特殊进程, 通常程序文件/sbin/init 进程id是1,在系统启动时负责启动各种系统服务, 之后就负责清理子进程, 只要有子进程终止, init就会调用wait函数清理它

      函数原型: #include <sys/types.h>  #include <sys/wait.h>

            pid_t wait(int *status);

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

       返回值 : 如果调用成功返回子进程id,调用失败返回-1

      父进程调用wait或waitpid时可能会: 

                  阻塞(如果它的所有子进程都还在运行)

                  带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)

                  出错立即返回(如果它么有子进程)

      这两个函数的区别 : 

            如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0

            wait等待第一个终止的子进程,而waitpid可一个通过pid参数指定等待哪一个子进程

      wait函数作用 ; 

            使用wait和waitpid可以获得子进程的终止信息。

            可以使父进程阻塞等待子进程终止,起到进程间同步的作用

            清理子进程

    扩展 ; 低字节判断信号, 高字节判断退出状态

  英语 ; abnormally(异常)    Executive(执行)

原文地址:https://www.cnblogs.com/cxw825873709/p/3309139.html