1. 程式人生 > >Unix環境高級編程(五)進程環境

Unix環境高級編程(五)進程環境

編輯 例程 令行 空間 調用出錯 程序 number 正常 getrlimit

  本章主要介紹了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(),也可以非自願的由一個信號使其終止。

寫個程序進程練習,程序如下:

 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); //刪除環境表中所有項

寫個程序進行環境變量的讀取設置及刪除。程序如下:

 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設置一個值,說明函數調用出錯。寫個程序來表達用法,程序如下:

 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);

關於進程資源限制目前還不知道有何用,以後再來補充。

Unix環境高級編程(五)進程環境