📓 APUE 一書的第七章學習筆記。java
有 8 種方式可使得進程終止,5 種爲正常方式:數組
main
exit()
_exit
or _Exit
pthread_exit
from the last thread3 種非正常終止方式:bash
abort
函數原型:架構
#include <stdlib.h> void exit(int status); void _Exit(int status); #include <unistd.h> void _exit(int status);
區別:_exit/_Exit
會當即進入內核;exit
先執行清理處理(對全部打開的 Stream 執行 fclose
),後進入內核。函數
exit(k)
至關於在 main
函數中 return k
,最近一個進程的退出碼能夠在 Shell 中使用 echo $?
獲取。佈局
按照 ISO C 標準,一個進程最多能夠登記 32 個回調函數,這些函數稱爲終止處理程序 (exit handler),由 exit
來調用。學習
函數原型:spa
int atexit(void (*func)(void)); // Returns: 0 if OK, nonzero on error
exit
調用終止處理函數的順序與登記順序相反(_exit/_Exit
則不會調用);若是登記屢次,也會被調用屢次。命令行
例子:指針
void test1() { printf("A "); } void test2() { printf("B "); } int main() { atexit(test1); atexit(test1); atexit(test2); // 若是調用下面 2 個函數,則不會有輸出 // _exit(0), _Exit(0) } // Output: B A A
下圖展現了一個 C 程序如何啓動和終止的過程,也顯示了 exit, _exit, _Exit, atexit
這 4 個函數的關係。
環境表 (Environment List), 與命令行參數 argv
同樣,是一個 char*
數組。
下列程序能夠打印全部的環境參數:
#include <stdio.h> extern char **environ; int main() { int i; for (i = 0; environ[i] != NULL; i++) puts(environ[i]); }
輸出一大片:
TERM=xterm-256color SHELL=/bin/bash ... USER=sinkinben LS_COLORS=rs=0:di=01;... PATH=... MAIL=/var/mail/sinkinben PWD=/home/sinkinben/workspace/apue HOME=/home/sinkinben ... _=./a.out
以下圖所示,一個 C 程序由如下部分組成:
static
修飾的變量。exec
初始化爲 0 或者空指針。(確實,我還覺得是隨機值)這是一種典型的邏輯佈局,但不是全部的實現都是如此,具體取決於實際的 OS 和硬件。對於 32 位 Intel x86 架構的 Linux,text 段從 0x80480000 開始,棧從 0xC0000000 開始向低地址增加。
能夠經過 size
命令獲取一個 C 程序的各個段大小,dec, hex
分別是前 3 個數字的總和的十進制和十六進制:
$ size /bin/bash text data bss dec hex filename 997958 36496 23480 1057934 10248e /bin/bash
共享庫 (Shared Libraries): 對於一些經常使用的公共函數庫,只須要在全部進程均可引用的存儲區保存一份副本。程序第一次調用某個庫函數的同時,用動態連接的方式將程序與庫函數相連接。這就減小了可執行文件的大小,但增長了一些運行時開銷。
使用 Shared Libraries 的另一個優勢是:能夠動態更新某個庫的版本,而不須要從新對使用該庫的程序從新連接。
使用 gcc -static
可指定生成的可執行文件使用靜態連接。
$ gcc test.c ; size ./a.out text data bss dec hex filename 1099 544 8 1651 673 ./a.out $ gcc test.c -static ; size ./a.out text data bss dec hex filename 823142 7284 6360 836786 cc4b2 ./a.out
相關函數:
#include <stdlib.h> void *malloc(size_t size); void *calloc(size_t nobj, size_t size); void *realloc(void *ptr, size_t newsize); // All three return: non-null pointer if OK, NULL on error void free(void *ptr);
做用:
malloc
: 申請指定字節數的內存,該內存的值不肯定。calloc
: 爲指定數量,指定長度的對象分配內存,並初始化爲 0 。realloc
: 增長或者減小 ptr
指向內存區的長度。當增長長度時,可能須要將以前的數據拷貝到另一個足夠大的內存區(也有多是在原有基礎上增長一段連續內存),新增區域的初始值不肯定。#include <stdlib.h> char *getenv(const char *name); // Returns: pointer to value associated with name, NULL if not found
獲取環境變量。例子:
#include <stdio.h> #include <stdlib.h> int main() { puts(getenv("JAVA_HOME")); } // Output: /usr/local/java/jdk1.7
相關 API:
#include <stdlib.h> int putenv(char *str); // Returns: 0 if OK, nonzero on error int setenv(const char *name, const char *value, int rewrite); int unsetenv(const char *name); // Both return: 0 if OK, −1 on error
改變當前進程以及後續產生的子進程的環境變量(其實是修改進程的環境表)。做用分別以下:
putenv
: 把 name=value
的環境變量添加到環境表,若是 name
已存在,則刪除原來的定義。setenv
: 將 name
設置爲 value
。rewrite = 0/1
表示是否覆蓋已有的 name
(若是有的話)。unsetenv
: 刪除 name
,若是不存在則什麼都不作。每一個進程都有一組資源限制,能夠經過 getrlimit, setrlimit
進行查詢和修改:
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlptr); int setrlimit(int resource, const struct rlimit *rlptr); // Both return: 0 if OK, −1 on error
resource
是形如 RLIMIT_CPU
的一組宏定義。
結構體 rlimit
的定義以下:
struct rlimit { rlim_t rlim_cur; /* soft limit: current limit */ rlim_t rlim_max; /* hard limit: maximum value for rlim_cur */ };
修改操做須要遵循如下規則:
cur <= max
rlim_max
,但必須大於等於 rlim_cur
.rlim_max
。修改資源限制會應當當前進程和它的子進程,因此 Shell 中通常會內置 ulimit
命令來修改當前 Shell 的資源限制。