zoukankan      html  css  js  c++  java
  • 《APUE》读书笔记—第七章进程环境

      本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制。

      main函数的原型为int main(int argc,char *argv[]);其中argc是命令行参数的数目,argv是指向参数的各个指针构成的数组。当内核执行C程序时,使用一个exec函数,在调用main函数前线调用一个特殊的启动例程,从内核获取命令行参数和环境变量。

      进程终止分为正常终止和异常终止。正常终止包括:(1)从main返回,(2)调用exit();(3)调用_exit或者_Exit();(4)最后启动一个线程从其启动例程返回;(5)最后一个线程调用pthread_exit。异常终止包括:(1)调用abort();(2)接收到一个信号并终止;(3)最后一个线程对取消请求做出响应。

    1、exit函数系列:_exit和_Exit函数立即进入内核,而exit函数则执行清理处理(如关闭标准I/O流,执行各终止处理程序)。在main函数执行return (0)与exit(0)是等价的。

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

     2、atexit函数,用来登记终止处理程序,一个进程可以登记多达32个函数,这些函数将有exit自动调用,调用顺序与登记顺序相反,同一个函数可以登记多次,则也会被调用多次。函数原型如下:

    #include <stdlib.h>
    int atexit(void (*function)(void));  //成功返回0,否则返回非0值

    一个C程序启动和终止的过程如下图所示:

    内核使程序执行的唯一方法是调用一个exec函数,终止的唯一方法是显式或者隐式地通过exit函数调用_exit()或_Exit(),也可以非自愿的由一个信号使其终止。

    写个程序进程练习,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void exit_func1();
     5 void exit_func2();
     6 
     7 int main()
     8 {
     9     //登记终止处理函数
    10     atexit(exit_func2);
    11     atexit(exit_func1);
    12     atexit(exit_func2);
    13     printf("Test exit and atexit.\n");
    14     exit(0);
    15 }
    16 
    17 void exit_func1()
    18 {
    19     printf("exit_func1() is called.\n");
    20 }
    21 void exit_func2()
    22 {
    23     printf("exit_func2() is called.\n");
    24 }

    程序执行结果如下:

      命令行参数,当执行一个程序时,调用exec的进程可将命令行参数传递给该新程序,进程间通信数据传输进程用到。写个程序输出其命令行参数,程序如下:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main(int argc,char *argv[])
     5 {
     6     int i;
     7     for(i=0;i<argc;++i)
     8         printf("argv[%d]: %s\n",i,argv[i]);
     9     exit(0);
    10 }

    测试结果如下:

    C程序的存储空间布局:

    存储器分配函数:

    #include <stdlib.h>
    void *malloc(size_t size);
    void *calloc(size_t nmemb,size_t size);
    void *realloc(void *ptr, size_t size); //更改以前分配区的长度

    void free(void *ptr);

    写个程序练习函数的使用:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 
     5 int main()
     6 {
     7     int n;
     8     int *pData;
     9     printf("Enter the number: ");
    10     scanf("%d",&n);
    11     pData = (int*)malloc(sizeof(int)*n);
    12     memset(pData,0,sizeof(int)*n);
    13     printf("pData address is :%p\n",pData);
    14     free(pData);
    15     pData = (int*)calloc(n,sizeof(int));
    16     printf("pData address is :%p\n",pData);
    17     pData=realloc(pData,sizeof(int)*(n+10));
    18     printf("pData address is :%p\n",pData);
    19     free(pData);
    20     exit(0);
    21 }

    环境变量:形式为name=value,环境变量可以在用进程进程间通信,exec函数可以通过环境变量进程传参数,例如在CGI程序中用到HTTP协议get和post方法对应的环境变量。环境变量可用于所有的子进程,这包括编辑器、脚本和应用。环境变量操作函数如下:

    #include <stdlib.h>
    char *getenv(const char *name); //指向与name关联的value的指针
    int putenv(char *string);  //取形式为name=value的字符串,将其放到环境表中
    int setenv(const char *name, const char *value, int overwrite); //将name设置为value
    int unsetenv(const char *name);  //删除name的定义

    int clearenv(void); //删除环境表中所有项

    写个程序进行环境变量的读取设置及删除。程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 
     5 int main()
     6 {
     7     char *name;
     8     char *value;
     9     char *str = "LENGTH=10";
    10     char *pvalue;
    11     name = "QUERY";
    12     value = "Hello,world";
    13     //设置环境变量,1表示若那么存在,则先先删除
    14     setenv(name,value,1);
    15     //用字符串设置环境变量
    16     putenv(str);
    17     //取环境变量的值
    18     pvalue = getenv(name);
    19     printf("%s=%s\n",name,pvalue);
    20     pvalue = getenv("LENGTH");
    21     printf("LENGTH=%s\n",pvalue);
    22     unsetenv("LENGTH");
    23     //取系统HOME环境变量的值
    24     pvalue = getenv("HOME");
    25     printf("HOME=%s\N",pvalue);
    26     exit(0);
    27 }

     程序执行结果如下:

    全局跳转函数setjmp和longjmp:解决跨越函数跳跃,处理发生在深层次嵌套函数调用中出错情况非常有用。全局或者静态变量的值在执行longjmp是保持不变。函数原型如下:

    int clearenv(void);
    #include <setjmp.h>
    int setjmp(jmp_buf env);  //返回值为0为直接调用,从longjmp调用返回非0值
    int sigsetjmp(sigjmp_buf env, int savesigs);

      一般用法是:设置一个全局的jmp_buf变量,在主进程中调用setjmp()设置跳转变量,如果后面的函数出现错误,调用longjmp设置一个值,说明函数调用出错。写个程序来表达用法,程序如下:

    View Code
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <setjmp.h>
     5 
     6 void func1();
     7 void func2();
     8 void func3();
     9 //定义一个全局的跳转变量
    10 jmp_buf jmpbuffer;
    11 
    12 int main()
    13 {
    14     int ret;
    15     //获取返回值,0为直接调用
    16     ret=setjmp(jmpbuffer);
    17     switch(ret)
    18     {
    19     case 1:
    20         printf("func1 is error.\n");
    21         exit(-1);
    22     case 2:
    23         printf("func2 is error.\n");
    24         exit(-1);
    25     case 3:
    26         printf("func3 is error.\n");
    27         exit(-1);
    28     }
    29     func1();
    30     exit(0);
    31 }
    32 void func1()
    33 {
    34     //longjmp(jmpbuffer,1);
    35     func2();
    36 }
    37 void func2()
    38 {
    39     //longjmp(jmpbuffer,2);
    40     func3();
    41 }
    42 void func3()
    43 {
    44     //设置跳转
    45     longjmp(jmpbuffer,3);
    46 }

    程序执行结果如下:

    进程资源限制函数:getrlimit和setrlimit,资源结果和函数原型如下:

    struct rlimit {
        rlim_t rlim_cur;  /* Soft limit */
        rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) */
    };

    #include <sys/resource.h>
    int getrlimit(int resource, struct rlimit *rlim);
    int setrlimit(int resource, const struct rlimit *rlim);

    关于进程资源限制目前还不知道有何用,以后再来补充。

  • 相关阅读:
    如何设计工作流引擎?
    产品特点概述驰骋工作流
    驰骋工作流程如何与您的系统进行耦合
    进制转换
    DNS欺骗(转) Anny
    Remember My Account Number(2 schema) Anny
    Mysql中的临时表使用方法(转) Anny
    Mysql任务调度(Event Schedular) Anny
    Using ssh connect to Amazon EC2 instance Anny
    Amazon EC2名词项目笔记(转) Anny
  • 原文地址:https://www.cnblogs.com/Anker/p/2819523.html
Copyright © 2011-2022 走看看