編輯:關於Android編程
進程等待
一個進程在終止時會關閉所有的文件描述符,釋放在用戶空間分配出來的內存,但它的PCB還保留著,而且內核中還保存著一些信息,如果是正常終止,則保存著退出狀態,如果是異常終止,則保存著導致該進程終止信號是哪個,。這個進程的父進程可以調用wait和waitpid獲取這些信息,然後徹底清除這個進程。
一個進程的父進程是shell進程,當它終止時shell就會調用wait或者waitpid得到它的退出狀態,然後清除這個進程。當一個進程正常或者異常終止的時候,內核就會向父進程發送SIGCHLD信號,對於這種信號,系統默認動作是忽略它。
【調用wait或者waitpid的進程會發生什麼情況?】
(1)如果這個進程的所有子進程都還在運行,則這個進程就會阻塞。
(2)如果一個子進程已終止,正等待父進程獲取其終止狀態,則取得該子進程的終止狀態後立即返回。
(3)如果這個進程它沒有任何子進程,則立即出錯返回。
頭文件:
#include
#include
1)pid_t wait(int *status);
返回值:成功返回被等待進程pid,失敗返回-1
參數:輸出型參數,獲取進程退出狀態,不關心則可以設置為NULL
如果進程由於接收到SIGCHLD而調用wait,則可期望wait會立即返回;但如果在任意時刻調用wait,則進程可能阻塞。
在一個子進程終止前, wait使其調用者堵塞,而waitpid有一個選項,可使調用者不堵塞。如果status不是空指針,則終止進程的終止狀態就存放在它所指的單元內。如果不關心終止狀態,則可將參數設置為空指針(waitpid同樣適用)。
例:
運行結果:
2)pid_t waitpid(pid_t pid, int *status, int options);
返回值:
a、當正常返回的時候waitpid返回收集到的子進程的進程id
b、如果設置了選項WNOHANG,而調用中waipid發現沒有已退出的子進程可收集,則返回0
c、如果調用中出錯,則返回-1,這時errno會被設置成相應的值以指示錯誤所在
d、當pid所指示的子進程不存在,或此進程存在,但不是調用進程的子進程,waitpid就會出錯返回,這時errno被設置為ECHILD
參數:
a、pid(進程id)
pid=-1;等待任一個子進程,與wait等效。
pid >0;等待其進程ID與pid相等的子進程。
pid == 0;等待其組id等於進程組id的任一個子進程。
pid <-1;等待其組ID等於pid絕對值的任一個子進程。
b、status(int型)
status的高8位(WIFEXITED(status)) :若為正常終止子進程返回的狀態,則為真。(查看進程是否是正常退出)
status的低8位 (WEXITSTATUS(status)) : 若WIFEXITED非零,提取子進程退出碼。(查看進程的退出碼)
例:
運行結果:
正常:
異常:exit(257);
3)檢查wait和waitpid所返回的終止狀態:
a、利用按位與,得到static的前8位和後8位
b、利用系統中的宏
WIFEXITED(status) : 若為正常終止子進程返回的狀態,則為真。
WEXITSTATUS(status) : 若WIFEXITED非零,返回子進程退出碼,提取進程退出返回值,如果子進程調exit(7),WEXITSTATUS(status就會返 回7。請注意,如果進程不是正常退出的,也就是說,WIFEXITED返回0,這個值就毫無意義。
說明:status 並不簡簡單單是一個整形變量,父進程和子進程之間所有的狀態交互都要通過這個int來表示,所以這個int的若干bit位都是有特殊的含義的,那麼這個“int”如何編碼就比較重要了,和IP地址一樣,它是比較緊湊的,或者說是比較擁擠的。
status指出了子進程是正常退出還是被非正常結束的(一個進程也可以被其他進程用信號結束),以及正常結束時的返回值,或被哪一個信號結束或進程的退出碼是多少等信息,這些信息都被放在整數的不同二進制位中,所以用常規的方法讀取會非常麻煩,所以開發者就設計了一套專門的宏(macro)來完成這項工作。
4)wait和waitpid的作用:
a、等待目的:子進程讀取到子進程退出的一個狀態信息
b、讓系統釋放掉子進程占有的僵屍狀態的資源
c、運行時不保證父子進程誰先運行,可保證子進程先退出,等待使父子進程的退出同步起來(即退出產生一定的順序)
5)waitpid提供了wait沒有提供的功能:
a、waitpid可等待一個特定的進程
b、waitpid提供了一個wait的非阻塞版本
c、waitpid支持作業控制
程序替換
用fork創建子進程後執行的是和父進程相同的程序,子進程往往要調用一種exec函數來執行另一個程序。當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序進行替換,從新程序的啟動例程開始執行,調用exec並不創建新的進程,所以調用exec前後該進程的id並未改變。
1)6種以exec開頭的函數:
#incldue
int execl(const char* path,const char* arg,....);
int execlp(const char* file,const char* arg,....);
int execle(const char* path,const char* arg,..., char* const emp[]);
int execv(const char* path,char* const argv[]);
int execp(const char* file,char* const argv[]);
int execve(const char* path,char* const argv[],char* const emp[]);
這些函數如果調用成功,則加載新的程序從啟動代碼開始執行,不再返回。如果調用出錯則返回-1,所以exec函數只有出錯的返回值而沒有成功的返回值。
2)這些函數的規則:
不帶字母p(表示path)的exec函數 第一個參數必須是程序的相對路徑或絕對路徑,例如"/bin/ls"或"./a.out",而不能 是"ls"或"a.out"。對於帶字母p的函數: 如果參數中包含/,則將其視為路徑名。 否則視為不帶路徑的程序名,在PATH環境變量的目錄列表中搜索這個程序。
帶有字母l( 表示list)的exec函數要求將新程序的每個命令行參數都當作一個參數傳給它,命令行參數的個數是可變的,因此函數原型中有...,...中的最後一個可變參數應該是NULL, 起sentinel的作用。
帶有字母v( 表示vector)的函數,則應該先構造一個指向各參數的指針數 組,然後將該數組的首地址當作參數傳給它,數組中的最後一個指針也應該是NULL,就像main函數的argv參數或者環境變量表一樣。
對於以e (表示environment)結尾的exec函數,可以把一份新的環境變量表傳給它,其他exec函數仍使用當前的環境變量表執行新程序。
例:
運行結果:
對我來說,寫自定義view是一個特麻煩但是寫完之後特有成就感的過程。寫完之後我總是喜歡拿給別人看,去炫耀(當然只是在自己熟悉和關系不錯的人群裡),盡管它們看起來會很簡陋。
IPC為進程間通信或跨進程通信,是指兩個進程進行進程間通信的過程。在PC和移動設備上一個進程指的是一個程序或者一個應用,所以我們可以將進程間通信簡單理解為不同應用之間的通
什麼是Glide?Glide是一個加載圖片的庫,作者是bumptech,它是在泰國舉行的google 開發者論壇上google為我們介紹的,這個庫被廣泛的運用在googl
開發中自定義鍵盤是否遇到文字發虛嗎??如下圖: vc+xvzwvcD4KPHA+Mi7X7rzytaW1xMrH1NprZXlib2FyZHZpZXfW0Mno1sPBv