《LINUX實(shí)操:關(guān)于Linux進(jìn)程環(huán)境》要點(diǎn):
本文介紹了LINUX實(shí)操:關(guān)于Linux進(jìn)程環(huán)境,希望對您有用。如果有疑問,可以聯(lián)系我們。
內(nèi)核執(zhí)行c法式時(shí),利用exec函數(shù)調(diào)用一個特殊的啟動例程,該啟動例程叢內(nèi)核中獲取命令行參數(shù)和環(huán)境變量值.
5種正常終止的情況:
(1)從main函數(shù)返回;
(2)挪用exit;
(3)挪用_exit和_Exit函數(shù);
(4)最后一個線程挪用pthread_exit;
(5)最后一個線程從其啟動例程返回;
3種異常終止情況
(1)調(diào)用abort;
(2)接到一個信號;
(3)最后一個線程對取消哀求做出響應(yīng);
一個進(jìn)程最多可以登記32和函數(shù)(例如:signal函數(shù)),這些函數(shù)由exit函數(shù)自動調(diào)用.在法式終止時(shí)調(diào)用這些函數(shù),形成終止處理法式,來進(jìn)行結(jié)束進(jìn)程前的收尾工作.而exit函數(shù)通過atexit函數(shù)的登記記錄來判斷調(diào)用哪些函數(shù).
此函數(shù)由ISO C 定義,其操作包含處理終止處理程序,然后關(guān)閉所有標(biāo)準(zhǔn)I/O流.需要注意的是,它不會處理文件描述符、多進(jìn)程(父子進(jìn)程)以及作業(yè)控制.
無論進(jìn)程怎樣結(jié)束,它都會在內(nèi)核上執(zhí)行同一段代碼(由進(jìn)程啟動和退出圖可知).這段代碼來關(guān)閉所有的文件描述符,釋放所有的存儲空間.
程序退出后,利用退出碼告知該進(jìn)程的父進(jìn)程.父進(jìn)程通過wait或waitpid函數(shù)來完成該子進(jìn)程的善后工作(獲取子進(jìn)程相關(guān)信息 釋放子進(jìn)程占用資源).若父進(jìn)程沒有處理子進(jìn)程的退出狀態(tài),則子進(jìn)程釀成僵死進(jìn)程.相反的,若父進(jìn)程在子進(jìn)程前終止,則子進(jìn)程釀成孤兒進(jìn)程.孤兒進(jìn)程會由1號進(jìn)程(init進(jìn)程)接收,大致過程如下:
(1)進(jìn)程終止時(shí),內(nèi)核逐個檢查所有活動的進(jìn)程;
(2)分析查找該終止進(jìn)程的子進(jìn)程;
(3)將該進(jìn)程的子進(jìn)程的父進(jìn)程ID改為1;
程序正?;虍惓=K止時(shí),內(nèi)核都會向父進(jìn)程發(fā)送SIGNAL信號.子進(jìn)程終止是異步事件,所以該信號也是異步信號.而該信號一般會被父進(jìn)程默認(rèn)忽略.或者提供一個信號處理函數(shù)來善后.wait和waitpid函數(shù)便是其中的信號處理函數(shù)的一部分.
wait和waitpid函數(shù)區(qū)別如下:
(1)wait會阻塞調(diào)用者進(jìn)程期待直至第一個終止的子進(jìn)程到來;
(2)waitpid可以通過參數(shù)設(shè)置,來實(shí)現(xiàn)調(diào)用者進(jìn)程不阻塞,或選擇要阻
塞期待的子進(jìn)程;
這里的調(diào)用者指的是父進(jìn)程
和環(huán)境變量相關(guān)的函數(shù)如下:
#include<stdlib.h>
char *getenv(const char *name);
返回值:指向與name關(guān)聯(lián)的value的指針;若未找到,返回NULL
int putenv(char *str);
返回值:若成功,返回0;若出錯,返回非0
int setenv(const char *name, const char *value,
int rewrite);
int unsetenv(const char *name);
兩個函數(shù)返回值:若成功,返回0;若出錯,返回-1
環(huán)境表和環(huán)境字符串通常存放在內(nèi)存空間的高地址處(頂部).所以在修改它的值時(shí),內(nèi)存是不克不及繼續(xù)向高地址延伸;但又因?yàn)?它之下是各個棧幀,所以也不克不及向下延伸.如何修改它的值的過程如下:
(1)改動環(huán)境表
1)新value <= 舊value,直接覆蓋舊value的存儲空間
2)新value >= 舊value,調(diào)用malloc函數(shù),在堆區(qū)開辟新的存儲空間,
將新value復(fù)制到這里,再將這片存儲區(qū)首地址寫到環(huán)境表相應(yīng)的地位處.
(2)新增環(huán)境表
1)新增一個環(huán)境變量,調(diào)用malloc函數(shù)開辟新的存儲空間,將本來的環(huán)
境表復(fù)制到該存儲區(qū),其次再添加一個環(huán)境變量,然后在尾部賦值為NULL,
最后將environ指向該區(qū)域;
2)在 1)過程的基礎(chǔ)上,調(diào)用realloc函數(shù),多次添加環(huán)境變量;
注意:以這種方式修改的環(huán)境變量只在當(dāng)下程序運(yùn)行時(shí)有效,當(dāng)程序結(jié)束時(shí),相應(yīng)的存儲區(qū)被系統(tǒng)回收,這些修改就會失效.
#include<stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nojy, size_t size);
void *realloc(void *ptr, size_t newsize);
3個函數(shù)返回值:若成功,返回非空指針;若出錯,返回NULL
注意:這些動態(tài)分配的函數(shù)一般在分配存儲空間時(shí),會比要求的大.因?yàn)樵陂_辟空間的前后部分存儲記錄管理信息.因此,在使用時(shí),千萬不要越界拜訪,以免造成不可預(yù)知的后果.
在c語言中,goto語句是不克不及跨函數(shù)跳轉(zhuǎn)的.尤其是在函數(shù)深層調(diào)用時(shí)的跳轉(zhuǎn)需求,在出錯處理的情況下非常有用.
#include<setjmp.h>
int setjmp(jmp_buf env);
返回值:若直接調(diào)用,返回0;若從longjmp返回,返回非0
void longjmp(jmp_buf env, int val);
變量值回滾問題:自動變量和寄存器變量會存在回滾現(xiàn)象.利用volatile屬性來避免此類情況的產(chǎn)生.(在給變量賦值時(shí),賦的值回首先存儲在內(nèi)存(存儲器變量)中,然后在由cpu取走,存儲在cpu的寄存器上(寄存器變量).在做系統(tǒng)優(yōu)化時(shí),那些頻繁使用的變量,會直接存儲到寄存器中而不經(jīng)過內(nèi)存.)
在調(diào)用setjmp函數(shù)時(shí),內(nèi)核會把當(dāng)前的棧頂指針保存在env變量中,所以在調(diào)用longjmp函數(shù)返回該位置時(shí),全局變量、靜態(tài)變量、易失變量和自動變量如果在調(diào)用setjmp和longjmp函數(shù)之間它們的值被修改過,是不會回滾到setjmp函數(shù)調(diào)用之前的值(當(dāng)然,編譯器將auto變量優(yōu)化為寄存器變量除外).因?yàn)?這些存儲器變量的值是存儲在內(nèi)存相應(yīng)的段中,回到原先棧頂狀態(tài)時(shí),同樣拜訪的還是原先的內(nèi)存空間.
然而,對于寄存器變量來說,首先要明確一點(diǎn):寄存器變量是用動態(tài)存儲的方式.意思是寄存器變量的值可能存在分歧的寄存器中.如果在調(diào)setjmp和longjmp函數(shù)之間它們的值被修改過,這個值可能不會存到setjmp之前的對其賦值的寄存器中,而在調(diào)用longjmp函數(shù)后,又回到了調(diào)用setjmp函數(shù)時(shí)的狀態(tài).這個時(shí)候再讀取寄存器變量的值時(shí),讀到的是原先那個寄存器中存儲的值而不是修改過的那個寄存器中存儲的值,所以出現(xiàn)的回滾現(xiàn)象.
本文永遠(yuǎn)更新鏈接地址:
維易PHP培訓(xùn)學(xué)院每天發(fā)布《LINUX實(shí)操:關(guān)于Linux進(jìn)程環(huán)境》等實(shí)戰(zhàn)技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培養(yǎng)人才。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/7683.html