zoukankan      html  css  js  c++  java
  • Linux/UNIX之进程环境

    进程环境

    进程终止

    有8种方式使进程终止,当中5中为正常终止,它们是

    1)      从main返回

    2)      调用exit

    3)      调用_exit或_Exit

    4)      最后一个线程从其启动例程返回

    5)      最后一个线程调用pthread_exit

    异常终止有3中方式

    6)      调用abort

    7)      接到一个信号并终止

    8)      最后一个线程对取消请求做出对应

    exit函数

    #include <stdlib.h>

    void exit(int status);

    void _Exit(int status);

    #include <unistd.h>

    void _exit(int status);

             三个函数都带有一个整形參数,成为终止状态。

    exit函数总是先运行一个标准I/O库的清理关闭操作:为所以打开流调用fclose函数,这会造成所以缓冲区的输出数据都被冲洗。

    exit(0)等价于return(0)。

    atexit函数

    依照ISO C的规定,一个进程能够登记多达32个函数,这些函数将由exit自己主动调用。我们称这些函数为终止处理程序,并调用atexit函数来登记这些函数。

    #include <stdlib.h>
    int atexit(void (*function)(void));
    当中,atexit的參数是一个函数地址,当调用此函数时无需向它传送不论什么參数,也不期望它返回一个值。exit调用这些函数的顺序与他们被atexit登记的顺序相反。同一函数如登记多次,则也会被调用多次。例如以下是使用atexit的程序。
    #include "stdlib.h"
    #include "stdio.h"
    static void my_exit1(void);
    static void my_exit2(void);
     
    int main(void)
    {
       if (atexit(my_exit2) != 0)
           perror("can't register my_exit2");
     
       if (atexit(my_exit1) != 0)
           perror("can't register my_exit1");
       if (atexit(my_exit1) != 0)
           perror("can't register my_exit1");
     
       printf("main is done
    ");
        return(0);
    }
    static void my_exit1(void)
    {
       printf("first exit handler
    ");
    }
     
    static void my_exit2(void)
    {
       printf("second exit handler
    ");
    }


    输出结果例如以下:

    main is done

    first exit handler

    first exit handler

    second exit handler

    命令行參数

    内核是程序运行的唯一方法是调用exec函数。当运行一个程序时,exec的进程可将命令行參数传递给该新程序。

    C程序的存储空间布局

    正文段:这是由CPU运行的机器指令部分。通常正文段是能够共享的。

    初始化数据段:通常将此段成为数据段。包括程序中明白赋初值的全局变量或静态变量。

    非初始化数据段:通常称此段为BBS段(block startedby ymbol),未赋初值的全局变量或静态变量。在程序运行之前,内核将此段的数据初始化为0或空指针。

    栈:自己主动变量以及每次函数调用时所需保存的信息都存放在此段中。

    堆:通常在堆中进行动态存储分配。

    C程序典型的存储安排例如以下所看到的:


    用size命令报告正文段、数据段和bbs段的长度。

    环境表和环境变量

    环境表

    每个程度都会接收到一张环境表。环境表是一个字符指针数组,当中每个指针包括一个以null结束的C字符串的地址。全局变量environ则包括了该指针数组的地址:

    extern char**environ

             比如,假设该环境包括5个字符串,则其示意图例如以下


    当中每一个字符串结尾都显示的有一个null字符。我们称environ为环境指针,指针数组为环境表,当中各个指针所指字符串为环境字符串。

    环境变量

    环境字符串的形式通常例如以下:

    name = value

    ISO C定义了一个函数getenv用于取环境变量值:

    #include <stdlib.h>

    char *getenv(const char *name);

    此函数返回一个指针,指向name = value字符串中的value。未找到返回NULL。

    #include <stdlib.h>

    int putenv(char *string);

    int setenv(const char *name, const char*value, int overwrite);

    int unsetenv(const char *name);

    putenv取形式为name = value的字符串,将其放到环境表中。假设name已近存在,则先删除原定义。

    setenv将name设置为value。

    unsetenv删除name的定义。

    环境表和环境字符串通常存储在空间的顶部(栈之上)

    setjmp和longjmp

    C语言中goto是不能跨越函数的,运行这类跳转功能的函数是setjmp和longjmp。

    #include <setjmp.h>

    int setjmp(jmp_buf env);

    void longjmp(jmp_buf env, int val);

    通过程序来看看自己主动变量、全局变量、寄存器变量、静态变量和易失变量的不同情况:

    #include <stdio.h>
    #include <setjmp.h>
     
    static void f1(int, int, int, int);
    static void f2(void);
     
    static jmp_buf  jmpbuffer;
    static int      globval;
     
    int main(void)
    {
       int             autoval;
       register int    regival;
       volatile int    volaval;
       static int      statval;
     
       globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;
     
       if (setjmp(jmpbuffer) != 0) {
           printf("after longjmp:
    ");
           printf("globval = %d, autoval = %d, regival = %d,"
    " volaval = %d, statval = %d
    ",
               globval, autoval, regival, volaval, statval);
           exit(0);
        }
     
       /*
        * Change variables after setjmp, but before longjmp.
        */
       globval = 95; autoval = 96; regival = 97; volaval = 98;
       statval = 99;
     
       f1(autoval, regival, volaval, statval); /* never returns */
       exit(0);
    }
     
    static void
    f1(int i, int j, int k, int l)
    {
       printf("in f1():
    ");
       printf("globval = %d, autoval = %d, regival = %d,"
           " volaval = %d, statval = %d
    ", globval, i, j, k, l);
       f2();
    }
     
    static void
    f2(void)
    {
       longjmp(jmpbuffer, 1);
    }


    其运行结果例如以下:

    in f1():

    globval = 95, autoval = 96, regival = 97,volaval = 98, statval = 99

    after longjmp:

    globval = 95, autoval = 2, regival = 3,volaval = 98, statval = 99

    可见全局变量、静态变量和易失变量不受影响,自己主动变量和寄存器变量是否变化是不确定的(虽然这里显示恢复setjmp的值)。

    getrlimit和setrlimit函数

    #include <sys/time.h>

    #include <sys/resource.h>

    int getrlimit(int resource, struct rlimit*rlim);

    int setrlimit(int resource, const structrlimit *rlim);

    每一个进程都有一组资源限制,当中一些能够用getrlimit和setrlimit函数查询和更改。进程的资源限制一般是在系统初始化时由进程0建立的,然后由每一个后序进程继承。

  • 相关阅读:
    继承与多态
    欢迎来到vmax-tam的博客
    MySQL令人咋舌的隐式转换
    MySQL数据库SQL语句(高级进阶二,图文详解)
    深入浅出MySQL之索引为什么要下推?
    【推荐】开源项目ElasticAmbari助力 ElasticSearch、Kibana、ambari服务高效运维管理
    Java集合篇:Map集合的几种遍历方式及性能测试
    大厂Redis高并发场景设计,面试问的都在这!
    第八届“图灵杯”NEUQ-ACM程序设计竞赛(全题解&&详细)
    11个编程接单的网站,你有技术就有收入,有收入就有女朋友《男盆友》
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4037437.html
Copyright © 2011-2022 走看看