




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、嵌入式Linux應(yīng)用程序開發(fā),主講人:方攀 Email: Blog:,嵌入式Linux應(yīng)用程序開發(fā),嵌入式Linux應(yīng)用程序開發(fā)及交叉編譯:Hello World ! 嵌入式Linux內(nèi)核模塊開發(fā):Hello Module! Linux環(huán)境下多進(jìn)程及多線程編程,1.1 Linux應(yīng)用程序介紹,在為Linux開發(fā)應(yīng)用程序時(shí),絕大多數(shù)情況下使用的都是C語言,因此幾乎每一位Linux程序員面臨的首要問題都是靈活運(yùn)用C編譯器.目前Linux下最常用的C語言編譯器是GCC(GNU Compiler Collection),它是GNU項(xiàng)目中符合ANSIC標(biāo)準(zhǔn)的編譯系統(tǒng),能夠編譯用C、C+和Object C
2、等語言編寫的程序.GCC不僅功能非常強(qiáng)大,結(jié)構(gòu)也異常靈活.最值得稱道的一點(diǎn)就是它可以通過不同的前端模塊來支持各種語言,如Java、Fortran、Pascal、Modula-3和Ada等. 開放自由和靈活是Linux的魅力所在,而這一點(diǎn)在GCC上的體現(xiàn)就是程序員通過它能夠更好地控制整個(gè)編譯過程.在使用GCC編譯程序時(shí),編譯過程可以被細(xì)分為四個(gè)階段: 預(yù)處理(Pre-Processing) 編譯(Compiling) 匯編(Assembling) 鏈接(Linking) Linux程序員可以根據(jù)自己的需要讓GCC在編譯的任何階段結(jié)束,以便檢查或使用編譯器在該階段的輸出信息,或者對(duì)最后生成的二進(jìn)制
3、文件進(jìn)行控制,以便通過加入不同數(shù)量和種類的調(diào)試代碼來為今后的調(diào)試做好準(zhǔn)備.和其它常用的編譯器一樣,GCC也提供了靈活而強(qiáng)大的代碼優(yōu)化功能,利用它可以生成執(zhí)行效率更高的代碼 GCC提供了30多條警告信息和三個(gè)警告級(jí)別,使用它們有助于增強(qiáng)程序的穩(wěn)定性和可移植性此外,GCC還對(duì)標(biāo)準(zhǔn)的C和C+語言進(jìn)行了大量的擴(kuò)展,提高程序的執(zhí)行效率,有助于編譯器進(jìn)行代碼優(yōu)化,能夠減輕編程的工作量.,1.1 應(yīng)用程序起步編寫源文件,在/root/下建一個(gè)自己的目錄 #mkdir project #cd project #vim helloworld.c #include int main(void) printf(We
4、 love arm,we love sep4020!n); return 1; ,代碼注意問題,main函數(shù)的返回值應(yīng)該是int類型; main函數(shù)在終止前沒有調(diào)用“return 1;”語句來結(jié)尾。,1.2 編譯helloworld.c,(1)在pc機(jī)上編譯能在pc機(jī)上運(yùn)行的應(yīng)用程序的方法 # gcc -o helloworld_pc helloworld.c(這個(gè)是用i386的gcc編譯器編譯的,所以只能在pc機(jī)的linux環(huán)境中運(yùn)行) (2)在pc機(jī)上編譯能在sep4020板子上運(yùn)行的應(yīng)用程序的方法 # arm-linux-gcc -o helloworld_arm helloworld.
5、c(這個(gè)是用arm的交叉gcc編譯器編譯的,所以可以下載到板子上運(yùn)行),1.3運(yùn)行helloworld程序,(1)在pc機(jī)上運(yùn)行i386的程序 rootlocalhost code# ./helloworld_pc We love arm,we love sep4020! (2)在開發(fā)板上運(yùn)行應(yīng)用程序 將應(yīng)用程序helloworld_arm拷貝到/nfs/demo文件夾下 rootlocalhost code# cp helloworld_arm /nfs/demo / # cd demo /demo # ./helloworld_arm We love arm,we love sep4020
6、!,2.1 編寫Hello Module源代碼,前面我們介紹了一個(gè)簡單的Linux程序Hello World, 它是運(yùn)行于用戶態(tài)的應(yīng)用程序,現(xiàn)在我們?cè)俳榻B一個(gè)運(yùn)行于內(nèi)核態(tài)的 Hello Module程序,它其實(shí)是一個(gè)最簡單的驅(qū)動(dòng)程序模塊。 我們將Hello Module的源代碼放置于/root/project/module目錄,名稱為hellomodule.c,內(nèi)容如下:,#include #include MODULE_LICENSE(GPL); static int _init sep4020_hello_module_init(void) printk(Hello, sep4020 mo
7、dule is installed !n); return 0; static void _exit sep4020_hello_module_cleanup(void) printk(Good-bye, sep4020 module was removed!n); module_init(sep4020_hello_module_init); module_exit(sep4020_hello_module_cleanup);,2.2 編譯Hello Module源代碼,由于這個(gè)模塊是加到嵌入式linux的內(nèi)核中的,所以它肯定會(huì)用到許多嵌入式linux源碼的頭文件的,我們的嵌入式linux的
8、內(nèi)核源碼位置在/linux-3.2/下面,這中間的鏈接過程非常復(fù)雜,為了不讓我們手動(dòng)輸入編譯指令,一般編譯2.6 版本的驅(qū)動(dòng)模塊需要把驅(qū)動(dòng)代碼加入內(nèi)核代碼樹,并做相應(yīng)的配置,如下步驟 Step1:把剛才的源碼文件拷貝到/linux-3.2/drivers/char/sep4020_char目錄下 Step 2:編輯配置 /linux-3.2/drivers/char/sep4020_char 的Kconfig文件,加入驅(qū)動(dòng)選項(xiàng)( 注意tristate 前面有tab鍵) config SEP4020_HELLOMODULE tristate sep4020 hello module driver
9、 使之在 make menuconfig的時(shí)候出現(xiàn) ;,Step3: 修改Makefile文件,在其中加入: obj-$(CONFIG_SEP4020_HELLOMODULE) += hellomodule.o Step4:這時(shí)回到 /linux-3.2 源代碼根目錄位置,執(zhí)行 make modules,2.3 把 HelloModule 下載到開發(fā)板并安裝使用,3 Linux進(jìn)程編程,3.1 Linux進(jìn)程的概念 3.2 Linux下的進(jìn)程啟動(dòng) 3.3 進(jìn)程控制編程 3.4 守護(hù)進(jìn)程編程 3.5 進(jìn)程間通信,3.1 Linux進(jìn)程的概念,(1)進(jìn)程是一個(gè)獨(dú)立的可調(diào)度的活動(dòng); (2)進(jìn)程是一個(gè)
10、抽象實(shí)體,當(dāng)它執(zhí)行某個(gè)任務(wù)時(shí),將要分配和釋放各種資源(P. Denning) ; (3)進(jìn)程是可以并行執(zhí)行的計(jì)算部分。 以上進(jìn)程的概念都不相同,但其本質(zhì)是一樣的。它指出了進(jìn)程是一個(gè)程序的一次執(zhí)行的過程。它和程序是有本質(zhì)區(qū)別的,程序是靜態(tài)的,它是一些保存在磁盤上的指令的有序集合,沒有任何執(zhí)行的概念;而進(jìn)程是一個(gè)動(dòng)態(tài)的概念,它是程序執(zhí)行的過程,包括了動(dòng)態(tài)創(chuàng)建、調(diào)度和消亡的整個(gè)過程。它是程序執(zhí)行和資源管理的最小單位。,進(jìn)程控制塊 (1),進(jìn)程是 Linux 系統(tǒng)的基本調(diào)度單位,那么從系統(tǒng)的角度看如何描述并表示它的變化呢? 進(jìn)程標(biāo)識(shí)符:當(dāng)一個(gè)進(jìn)程產(chǎn)生時(shí),系統(tǒng)都會(huì)為它分配一個(gè)標(biāo)識(shí)符; 進(jìn)程所占的內(nèi)存區(qū)域
11、:每個(gè)進(jìn)程執(zhí)行時(shí)都需要占用一定的內(nèi)存區(qū)域,此區(qū)域用于保存該進(jìn)程所運(yùn)行的程序代碼和使用的程序變量。每一個(gè)進(jìn)程所占用的內(nèi)存是相互獨(dú)立的,因此改變一個(gè)進(jìn)程所占內(nèi)存中數(shù)據(jù)的任何改動(dòng),都只對(duì)該進(jìn)程產(chǎn)生影響,不會(huì)影響到其它進(jìn)程的順利執(zhí)行; 文件描述符:當(dāng)一個(gè)進(jìn)程在執(zhí)行時(shí),它需要使用一些相關(guān)的文件描述符。文件描述符描述了被打開文件的信息,不同的進(jìn)程打開同一個(gè)文件時(shí),所使用的文件描述符是不同的。一個(gè)進(jìn)程文件描述符的改變并不會(huì)對(duì)其它的進(jìn)程打開同一個(gè)文件的描述符產(chǎn)生任何影響;,進(jìn)程控制塊 (2),安全信息:一個(gè)進(jìn)程的安全信息包括用戶識(shí)別號(hào)和組識(shí)別號(hào); 進(jìn)程環(huán)境:一個(gè)進(jìn)程的運(yùn)行環(huán)境包括環(huán)境變量和啟動(dòng)該進(jìn)程的程序調(diào)用
12、的命令行; 信號(hào)處理:一個(gè)進(jìn)程有時(shí)需要用信號(hào)同其它進(jìn)程進(jìn)行通信。進(jìn)程可以發(fā)送和接收信號(hào),并對(duì)其作出相應(yīng)處理; 資源安排:進(jìn)程是調(diào)度系統(tǒng)資源的基本單位。當(dāng)多個(gè)進(jìn)程同時(shí)運(yùn)行時(shí),linux系統(tǒng)內(nèi)核安排不同進(jìn)程輪流使用系統(tǒng)的各種資源;,進(jìn)程控制塊 (3),同步處理:多個(gè)程序之間同步運(yùn)行的實(shí)現(xiàn),也是通過進(jìn)程來完成的。這將會(huì)使用到諸如共享內(nèi)存、文件鎖定等方法。 進(jìn)程狀態(tài):在一個(gè)進(jìn)程存在期間,每一時(shí)刻進(jìn)程都處在一定的狀態(tài),包括運(yùn)行、等待被調(diào)度或睡眠狀態(tài)。,進(jìn)程結(jié)構(gòu)體描述,進(jìn)程的標(biāo)識(shí),進(jìn)程的標(biāo)識(shí) :進(jìn)程號(hào)、父進(jìn)程號(hào)、父進(jìn)程組號(hào)、會(huì)話號(hào)、會(huì)話首領(lǐng)號(hào)都是用于從不同的側(cè)面來描述進(jìn)程的身份 測試進(jìn)程號(hào)的代碼: /*p
13、rocess.c*/ #include #include #include int main() /*獲得當(dāng)前進(jìn)程的進(jìn)程ID和其父進(jìn)程ID*/ printf(The PID of this process is %dn,getpid(); printf(The PPID of this process is %dn,getppid(); return 1; ,進(jìn)程狀態(tài),一個(gè)進(jìn)程在其生存期內(nèi),可處于一組不同的狀態(tài)下,稱為進(jìn)程狀態(tài) 運(yùn)行狀態(tài)(TASK_RUNNING)當(dāng)進(jìn)程正在被CPU 執(zhí)行,或已經(jīng)準(zhǔn)備就緒隨時(shí)可由調(diào)度程序執(zhí)行,則稱該進(jìn)程為處于運(yùn)行狀態(tài)(running)。進(jìn)程可以在內(nèi)核態(tài)運(yùn)行,也可
14、以在用戶態(tài)運(yùn)行; 可中斷睡眠狀態(tài)(TASK_INTERRUPTIBLE)當(dāng)進(jìn)程處于可中斷等待狀態(tài)時(shí),系統(tǒng)不會(huì)調(diào)度該進(jìn)行執(zhí)行。當(dāng)系統(tǒng)產(chǎn)生一個(gè)中斷或者釋放了進(jìn)程正在等待的資源,或者進(jìn)程收到一個(gè)信號(hào),都可以喚醒進(jìn)程轉(zhuǎn)換到就緒狀態(tài)(運(yùn)行狀態(tài));,不可中斷睡眠狀態(tài)(TASK_UNINTERRUPTIBLE)與可中斷睡眠狀態(tài)類似。但處于該狀態(tài)的進(jìn)程只有被使用wake_up()函數(shù)明確喚醒時(shí)才能轉(zhuǎn)換到可運(yùn)行的就緒狀態(tài)。 暫停狀態(tài)(TASK_STOPPED)當(dāng)進(jìn)程收到信號(hào)SIGSTOP、SIGTSTP、SIGTTIN 或SIGTTOU 時(shí)就會(huì)進(jìn)入暫停狀態(tài)??上蚱浒l(fā)送SIGCONT 信號(hào)讓進(jìn)程轉(zhuǎn)換到可運(yùn)行狀態(tài)。
15、 僵死狀態(tài)(TASK_ZOMBIE)當(dāng)進(jìn)程已停止運(yùn)行,但其父進(jìn)程還沒有詢問其狀態(tài)時(shí),則稱該進(jìn)程處于僵死狀態(tài)。,Linux下進(jìn)程的模式和類型,在 Linux 系統(tǒng)中,進(jìn)程的執(zhí)行模式劃分為用戶模式和內(nèi)核模式。如果當(dāng)前運(yùn)行的是用戶程序、應(yīng)用程序或者內(nèi)核之外的系統(tǒng)程序,那么對(duì)應(yīng)進(jìn)程就在用戶模式下運(yùn)行;如果在用戶程序執(zhí)行過程中出現(xiàn)系統(tǒng)調(diào)用或者發(fā)生中斷事件,那么就要運(yùn)行操作系統(tǒng)(即核心)程序,進(jìn)程模式就變成內(nèi)核模式。在內(nèi)核模式下運(yùn)行的進(jìn)程可以執(zhí)行機(jī)器的特權(quán)指令,而且此時(shí)該進(jìn)程的運(yùn)行不受用戶的干擾, 即使是 root 用戶也不能干擾內(nèi)核模式下進(jìn)程的運(yùn)行。 用戶進(jìn)程既可以在用戶模式下運(yùn)行,也可以在內(nèi)核模式下運(yùn)
16、行,,3.2 Linux下的進(jìn)程啟動(dòng),Linux 下啟動(dòng)一個(gè)進(jìn)程有兩種主要途徑:手工啟動(dòng)和調(diào)度啟動(dòng)。手動(dòng)啟動(dòng)是由用戶輸入命令直接啟動(dòng)進(jìn)程,而調(diào)度啟動(dòng)是指系統(tǒng)根據(jù)用戶的設(shè)置自行啟動(dòng)進(jìn)程。 (1)手工啟動(dòng) ,又可分為前臺(tái)啟動(dòng)和后臺(tái)啟動(dòng)。 前臺(tái)啟動(dòng),如“l(fā)s -l”; 后臺(tái)啟動(dòng)往往是在該進(jìn)程非常耗時(shí),且用戶也不急著需要結(jié)果的時(shí)候啟動(dòng)的,如“tftp gr tcpip.rar 返回值:0:子進(jìn)程 子進(jìn)程ID(大于0的整數(shù)):父進(jìn)程 1:出錯(cuò),子進(jìn)程是父進(jìn)程的拷貝,它具有和父進(jìn)程相同的代碼段,但是它具有自己的數(shù)據(jù)段和堆棧段。 子進(jìn)程將從父進(jìn)程獲得絕大部分屬性,但也會(huì)更改部分屬性的
17、值,要更改的屬性為: 進(jìn)程ID 進(jìn)程組ID(更改為父進(jìn)程ID) SESSION ID(為子進(jìn)程的運(yùn)行時(shí)間記錄) 所打開文件及文件的偏移量(父進(jìn)程對(duì)文件的鎖定),/*fork.c*/ #include #include #include #include int main(void) pid_t result; /*調(diào)用fork函數(shù),其返回值為result*/ result = fork(); /*通過result的值來判斷fork函數(shù)的返回情況,首先進(jìn)行出錯(cuò)處理*/ if(result = -1) perror(fork); exit; /*返回值為0代表子進(jìn)程*/ else if(resul
18、t = 0) printf(The return value is %dnIn child process!nMy PID is%dn,result,getpid(); /*返回值大于0代表父進(jìn)程*/ else printf(The return value is %dnIn father process!nMy PID is%dn,result,getpid(); return 1; ,編譯源文件fork.c并在板子上運(yùn)行,先在上位機(jī)編譯源文件: 進(jìn)入/nfs/project目錄下 rootlocalhost project# arm-linux-gcc -o fork fork.c 將可執(zhí)
19、行程序下載到目標(biāo)板上,運(yùn)行結(jié)果如下所示:,(2)exec函數(shù)族,exec 函數(shù)族就提供了一個(gè)在進(jìn)程中啟動(dòng)另一個(gè)程序執(zhí)行的方法。它可以根據(jù)指定的文件名或目錄名找到可執(zhí)行文件,并用它來取代原調(diào)用進(jìn)程的數(shù)據(jù)段、代碼段和堆棧段,在執(zhí)行完之后,原調(diào)用進(jìn)程的內(nèi)容除了進(jìn)程號(hào)外,其他全部被新的進(jìn)程替換了。另外,這里的可執(zhí)行文件既可以是二進(jìn)制文件,也可以是 Linux 下任何可執(zhí)行的腳本文件。 在Linux中使用exec函數(shù)族主要有兩種情況: (1)當(dāng)進(jìn)程認(rèn)為自己不能再為系統(tǒng)和用戶做出任何貢獻(xiàn)時(shí),就可以調(diào)用任何 exec 函數(shù)族讓自己重生; (2) 如果一個(gè)進(jìn)程想執(zhí)行另一個(gè)程序,那么它就可以調(diào)用 fork 函數(shù)
20、新建一個(gè)進(jìn)程,然后調(diào)用任何一個(gè) exec,這樣看起來就好像通過執(zhí)行應(yīng)用程序而產(chǎn)生了一個(gè)新進(jìn)程。 (這種情況非常普遍),exec函數(shù)族有下列6個(gè)函數(shù):,#include 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 envp); int execv(constchar* path,char* const argv); int execvp(c
21、onst char* file,char* const argv); int execve(const char* path, char* const argv,char * const envp);,Execlp實(shí)例,/*execlp.c*/ #include #include #include int main() if(fork()=0) /*調(diào)用execlp函數(shù),這里相當(dāng)于調(diào)用了“ps ”命令*/ if(execlp(ps,ps,NULL)0) perror(execlp error!); 將源碼文件execlp.c保存到/nfs/project目錄下并交叉編譯: rootlocalh
22、ost project# arm-linux-gcc -o execlp execlp.c,Execlp運(yùn)行,在該程序中,首先使用fork函數(shù)新建一個(gè)子進(jìn)程,然后在子進(jìn)程里使用 execlp函數(shù)。讀者可以看到,這里的參數(shù)列表就是在 shell中使用的命令名和選項(xiàng)。并且當(dāng)使用文件名的方式進(jìn)行查找時(shí),系統(tǒng)會(huì)在默認(rèn)的環(huán)境變量 PATH 中尋找該可執(zhí)行文件。讀者可將編譯后的結(jié)果下載到目標(biāo)板上,運(yùn)行結(jié)果如下所示:,Execle實(shí)例,/*execle.c*/ #include #include #include int main() /*命令參數(shù)列表,必須以NULL結(jié)尾*/ char *envp=PATH
23、:=/tmp:$PATH,NULL; if(fork()=0) /*調(diào)用execle函數(shù),注意這里也要指出env的完整路徑*/ if(execle(/usr/bin/env,env,NULL,envp)0) perror(execle error!); return 1; 將源碼文件execlp.c保存到/nfs/project目錄下并交叉編譯: rootlocalhost project# arm-linux-gcc -o execle execle.c,Execle運(yùn)行,exec函數(shù)族使用注意點(diǎn),在使用 exec 函數(shù)族時(shí),一定要加上錯(cuò)誤判斷語句。因?yàn)?exec 很容易執(zhí)行失敗,其中最常見
24、的原因有: 找不到文件或路徑,此時(shí)errno被設(shè)置為 ENOENT; 數(shù)組argv和envp忘記用NULL結(jié)束,此時(shí) errno被設(shè)置為 EFAULT; 沒有對(duì)應(yīng)可執(zhí)行文件的運(yùn)行權(quán)限,此時(shí)errno被設(shè)置為 EACCES。,(3)exit和_exit,終止進(jìn)程函數(shù),形式一: #include void exit(int status); 說明:exit()函數(shù)是標(biāo)準(zhǔn)C中提供的函數(shù)。它用來終止正在運(yùn)行的程序,將關(guān)閉所有被該文件打開的文件描述符 形式二: #include void _exit(intstatus) 說明:_exit()函數(shù)也可用于結(jié)束一個(gè)進(jìn)程,與exit函數(shù)不同的是,調(diào)用_exi
25、t()是為了關(guān)閉一些linux特有的退出句柄。,終止進(jìn)程函數(shù),形式三: #include int atexit(void(*function)(void); 說明:atexit函數(shù)在結(jié)束一個(gè)程序后,調(diào)用一個(gè)不帶參數(shù)同時(shí)也沒有返回值的函數(shù)。該函數(shù)名由function指針指向 形式四: #include void abort(void); 說明:abort()函數(shù)用來發(fā)送一個(gè)SIGABRT信號(hào),這個(gè)信號(hào)將使當(dāng)前進(jìn)程終止。 形式五: #include void assert(intexpression); 說明: assert是一個(gè)宏。調(diào)用assert函數(shù)時(shí),首先要計(jì)算表達(dá)式expression的值
26、,如果為0,則調(diào)用abort()函數(shù)結(jié)束進(jìn)程。,Exit實(shí)例,/*exit.c*/ #include #include #include int main(void) pid_t pid; if(pid=fork()0) exit(0); else if(pid=0) printf(go into child process!n); printf(child process PID:%d,getpid(); exit(0); else printf(go into parent process!n); printf(Parent process PID:%4d,getpid(); _exit(
27、0); return 0; ,Exit運(yùn)行,將源碼文件execlp.c保存到/nfs/project目錄下并交叉編譯: rootlocalhost project# arm-linux-gcc -o execle execle.c 將板子啟動(dòng)Linux,并掛載網(wǎng)絡(luò)文件系統(tǒng),然后進(jìn)入/project目錄下面,運(yùn)行exit實(shí)例:,(4)wait和waitpid,wait函數(shù)是用于使父進(jìn)程(也就是調(diào)用wait的進(jìn)程)阻塞,直到一個(gè)子進(jìn)程結(jié)束或者該進(jìn)程接到了一個(gè)指定的信號(hào)為止。 如果該父進(jìn)程沒有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束,則wait就會(huì)立即返回。 waitpid的作用和wait一樣, 但它并不一定要
28、等待第一個(gè)終止的子進(jìn)程, 它還有若干選項(xiàng),如可提供一個(gè)非阻塞版本的wait功能,也能支持作業(yè)控制。實(shí)際上 wait函數(shù)只是 waitpid函數(shù)的一個(gè)特例,在Linux內(nèi)部實(shí)現(xiàn)wait函數(shù)時(shí)直接調(diào)用的就是 waitpid函數(shù)。,wait函數(shù)調(diào)用形式: #include #include pid_t wait(int *status) 這里的status是一個(gè)整型指針,是該子進(jìn)程退出時(shí)的狀態(tài) status若為空,則代表任意狀態(tài)結(jié)束的子進(jìn)程 status若不為空,則代表指定狀態(tài)結(jié)束的子進(jìn)程 另外,子進(jìn)程的結(jié)束狀態(tài)可由Linux中一些特定的宏來測定 成功的話返回子進(jìn)程的進(jìn)程號(hào) ,失敗則返回-1,wai
29、tpid函數(shù)調(diào)用形式: #include #include pid_t waitpid(pid_tpid,int* stat_loc,int options); 作用:waitpid等待指定的子進(jìn)程直到子進(jìn)程返回,如果pid為正值則等待指定的進(jìn)程(pid);如果為0則等待任何一個(gè)組ID和調(diào)用者的組ID相同的進(jìn)程;為-1時(shí)等同于wait調(diào)用;小于-1時(shí)等待任何一個(gè)組ID等于pid絕對(duì)值的進(jìn)程。 參數(shù)含義:stat_loc和wait的意義一樣; options可以決定父進(jìn)程的狀態(tài),可以取下面兩個(gè)值: WNOHANG:當(dāng)沒有子進(jìn)程存在時(shí),父進(jìn)程立即返回; WUNTACHED:當(dāng)子進(jìn)程結(jié)束時(shí)waitp
30、id返回,但是子進(jìn)程的退出狀態(tài)不可得到.,/*waitpid.c*/ #include #include #include #include #include int main() pid_t pc,pr; pc=fork(); if(pc0) printf(Error fork.n); /*子進(jìn)程*/ else if(pc=0) /*子進(jìn)程暫停5s*/ sleep(5); /*子進(jìn)程正常退出*/ exit(0); /*父進(jìn)程*/ else /*循環(huán)測試子進(jìn)程是否退出*/ do /*調(diào)用waitpid,且父進(jìn)程不阻塞*/ pr=waitpid(pc,NULL,WNOHANG); /pr=wai
31、t(NULL); /*若子進(jìn)程還未退出,則父進(jìn)程暫停1s*/ if(pr=0) printf(The child process has not exitedn); sleep(1); while(pr=0); /*若發(fā)現(xiàn)子進(jìn)程退出,打印出相應(yīng)情況*/ if(pr=pc) printf(Get child %dn,pr); else printf(some error occured.n); ,Waitpid運(yùn)行,將源碼文件execlp.c保存到/nfs/project目錄下并交叉編譯: rootlocalhost project# arm-linux-gcc -o execle execle
32、.c 將板子啟動(dòng)Linux,并掛載網(wǎng)絡(luò)文件系統(tǒng),然后進(jìn)入/project目錄下面,運(yùn)行exit實(shí)例:,3.4 守護(hù)進(jìn)程編程,守護(hù)進(jìn)程,也就是通常所說的 Daemon 進(jìn)程,是 Linux 中的后臺(tái)服務(wù)進(jìn)程。它是一個(gè)生存期較長的進(jìn)程,通常獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。守護(hù)進(jìn)程常常在系統(tǒng)引導(dǎo)裝入時(shí)啟動(dòng),在系統(tǒng)關(guān)閉時(shí)終止。Linux系統(tǒng)有很多守護(hù)進(jìn)程,大多數(shù)服務(wù)都是通過守護(hù)進(jìn)程實(shí)現(xiàn)的。,創(chuàng)建守護(hù)進(jìn)程的步驟,創(chuàng)建子進(jìn)程, 父進(jìn)程退出,創(chuàng)建新會(huì)話,改變當(dāng)前目錄 為根目錄,重設(shè)文件 權(quán)限掩碼,關(guān)閉文件描述符,這是編寫守護(hù)進(jìn)程的第一步。由于守護(hù)進(jìn)程是脫離控制終端的,因此,完
33、成第一步后就會(huì)在 Shell 終端里造成一程序已經(jīng)運(yùn)行完畢的假象。之后的所有工作都在子進(jìn)程中完成,而用戶在Shell終端里則可以執(zhí)行其他的命令,從而在形式上做到了與控制終端的脫離。 /*父進(jìn)程退出*/ pid=fork(); if(pid0) exit(0); ,(1)創(chuàng)建子進(jìn)程,父進(jìn)程退出,(2)在子進(jìn)程中創(chuàng)建新會(huì)話 (setsid函數(shù)),這個(gè)步驟是創(chuàng)建守護(hù)進(jìn)程中最重要的一步 進(jìn)程組 :進(jìn)程組是一個(gè)或多個(gè)進(jìn)程的集合。進(jìn)程組由進(jìn)程組 ID 來惟一標(biāo)識(shí)。除了進(jìn)程號(hào)(PID)之外,進(jìn)程組ID 也一個(gè)進(jìn)程的必備屬性。 每個(gè)進(jìn)程組都有一個(gè)組長進(jìn)程,其組長進(jìn)程的進(jìn)程號(hào)等于進(jìn)程組 ID。且該進(jìn)程 ID 不
34、會(huì)因組長進(jìn)程的退出而受到影響。 會(huì)話期 :會(huì)話組是一個(gè)或多個(gè)進(jìn)程組的集合。通常,一個(gè)會(huì)話開始于用戶登錄,終止于用戶退出,在此期間該用戶運(yùn)行的所有進(jìn)程都屬于這個(gè)會(huì)話期。 setsid函數(shù)作用 setsid函數(shù)用于創(chuàng)建一個(gè)新的會(huì)話,并擔(dān)任該會(huì)話組的組長。調(diào)用setsid 有下面的 3 個(gè) 作用: 讓進(jìn)程擺脫原會(huì)話的控制。 讓進(jìn)程擺脫原進(jìn)程組的控制。 讓進(jìn)程擺脫原控制終端的控制。,(3)改變當(dāng)前目錄為根目錄,這一步也是必要的步驟。使用fork創(chuàng)建的子進(jìn)程繼承了父進(jìn)程的當(dāng)前工作目錄。由于在進(jìn)程運(yùn)行過程中,當(dāng)前目錄所在的文件系統(tǒng)(比如“/mnt/usb”等)是不能卸載的,這對(duì)以后的使用會(huì)造成諸多的麻煩(
35、比如系統(tǒng)由于某種原因要進(jìn)入單用戶模式) 。因此,通常的做法是讓“/”作為守護(hù)進(jìn)程的當(dāng)前工作目錄,這樣就可以避免上述的問題,當(dāng)然,如有特殊需要,也可以把當(dāng)前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函數(shù)是 chdir。,文件權(quán)限掩碼是指屏蔽掉文件權(quán)限中的對(duì)應(yīng)位。由于使用 fork函數(shù)新建的子進(jìn)程繼承了父進(jìn)程的文件權(quán)限掩碼,這就給該子進(jìn)程使用文件帶來了諸多的麻煩。因此,把文件權(quán)限掩碼設(shè)置為 0,可以大大增強(qiáng)該守護(hù)進(jìn)程的靈活性。設(shè)置文件權(quán)限掩碼的函數(shù)是 umask。在這里,通常的使用方法為umask(0)。,(4)重設(shè)文件權(quán)限掩碼,(5)關(guān)閉文件描述符,同文件權(quán)限掩碼一樣,用fork函數(shù)
36、新建的子進(jìn)程會(huì)從父進(jìn)程那里繼承一些已經(jīng)打開了的文件。這些被打開的文件可能永遠(yuǎn)不會(huì)被守護(hù)進(jìn)程讀或?qū)?,但它們一樣消耗系統(tǒng)資源,而且可能導(dǎo)致所在的文件系統(tǒng)無法卸下。 for(i=0;iMAXFILE;i+) close(i);,/*dameon.c創(chuàng)建守護(hù)進(jìn)程實(shí)例*/ #include #include #include #include #include #include #include #define MAXFILE 65535 int main() pid_t pc; int i,fd,len; char *buf=This is a Dameonn; len =strlen(buf); p
37、c=fork(); /第一步 if(pc0) exit(0); /*第二步*/ setsid(); /*第三步*/ chdir(/);,/*第四步*/ umask(0); for(i=0;iMAXFILE;i+) /*第五步*/ close(i); /*這時(shí)創(chuàng)建完守護(hù)進(jìn)程,以下開始正式進(jìn)入守護(hù)進(jìn)程工作*/ while(1) if(fd=open(/tmp/dameon.log,O_CREAT|O_WRONLY|O_APPEND,0600)0) perror(open); exit(1); write(fd, buf, len+1); close(fd); sleep(10); ,守護(hù)進(jìn)程運(yùn)行,
38、3.5 進(jìn)程間通信,(1)管道(Pipe)及有名管道(named pipe) :管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。 (2)信號(hào)(Signal) :信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,它是比較復(fù)雜的通信方式,用于通知接受進(jìn)程有某事件發(fā)生,一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求效果上可以說是一樣的。 (3)消息隊(duì)列:消息隊(duì)列是消息的鏈接表,包括 Posix 消息隊(duì)列 systemV 消息隊(duì)列。它克服了前兩種通信方式中信息量有限的缺點(diǎn),具有寫權(quán)限的進(jìn)程可以向消息隊(duì)列中按照一定的規(guī)則添加新消息;對(duì)消息隊(duì)列有讀權(quán)限的進(jìn)程則可
39、以從消息隊(duì)列中讀取消息。 (4)共享內(nèi)存:可以說這是最有用的進(jìn)程間通信方式。它使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,不同進(jìn)程可以及時(shí)看到對(duì)方進(jìn)程中對(duì)共享內(nèi)存中數(shù)據(jù)的更新。這種通信方式需要依靠某種同步機(jī)制,如互斥鎖和信號(hào)量等。 (5)信號(hào)量:主要作為進(jìn)程間以及同一進(jìn)程不同線程之間的同步手段。 (6)套接字(Socket) :這是一種更為一般的進(jìn)程間通信機(jī)制,它可用于不同機(jī)器之間的進(jìn)程間通信,應(yīng)用非常廣泛。,(1)管道通信,ps,內(nèi)核,管道,grep init,管道是 Linux 中進(jìn)程間通信的一種方式。這里所說的管道主要指無名管道,它具有如下特點(diǎn)。 它只能用于具有親緣關(guān)系的進(jìn)程之間的通信(也就是父
40、子進(jìn)程或者兄弟進(jìn)程之間) 。 它是一個(gè)半雙工的通信模式,具有固定的讀端和寫端。 管道也可以看成是一種特殊的文件,對(duì)于它的讀寫也可以使用普通的 read、write 等函數(shù)。但是它不是普通的文件,并不屬于其他任何文件系統(tǒng),并且只存在于內(nèi)存中。,創(chuàng)建管道,調(diào)用形式: #include int pipe(int fd2) 該函數(shù)創(chuàng)建的管道的兩端處于一個(gè)進(jìn)程中間,在實(shí)際應(yīng)用中沒有太大意義,因此,一個(gè)進(jìn)程在由pipe()創(chuàng)建管道后,一般再fork一個(gè)子進(jìn)程,然后通過管道實(shí)現(xiàn)父子進(jìn)程間的通信 管道的讀寫規(guī)則 : 管道兩端可分別用描述字fd0以及fd1來描述,需要注意的是,管道的兩端是固定了任務(wù)的。即一端只
41、能用于讀,由描述字fd0表示,稱其為管道讀端;另一端則只能用于寫,由描述字fd1來表示,稱其為管道寫端。 如果試圖從管道寫端讀取數(shù)據(jù),或者向管道讀端寫入數(shù)據(jù)都將導(dǎo)致錯(cuò)誤發(fā)生。 一般文件的I/O函數(shù)都可以用于管道,如close、read、write等等。,管道讀寫說明,/*pipe_rw.c*/ #include #include #include #include #include int main() int pipe_fd2; pid_t pid; char buf_r100; char* p_wbuf; int r_num; memset(buf_r,0,sizeof(buf_r); /
42、*創(chuàng)建管道*/ if(pipe(pipe_fd)0) printf(pipe create errorn); return -1; /*創(chuàng)建一子進(jìn)程*/,管道讀寫實(shí)例,if(pid=fork()=0) printf(n); /*關(guān)閉子進(jìn)程寫描述符,并通過使父進(jìn)程暫停2秒確保父進(jìn)程已關(guān)閉相應(yīng)的讀描述符*/ close(pipe_fd1); sleep(2); /*子進(jìn)程讀取管道內(nèi)容*/ if(r_num=read(pipe_fd0,buf_r,100)0) printf(%d numbers read from the pipe is %sn,r_num,buf_r); /*關(guān)閉子進(jìn)程讀描述符*
43、/ close(pipe_fd0); exit(0); else if(pid0) /*/關(guān)閉父進(jìn)程讀描述符,并分兩次向管道中寫入Hello Pipe*/ close(pipe_fd0); if(write(pipe_fd1,Hello,5)!= -1) printf(parent write1 success!n); if(write(pipe_fd1, Pipe,5)!= -1) printf(parent write2 success!n); /*關(guān)閉父進(jìn)程寫描述符*/ close(pipe_fd1); sleep(3); /*收集子進(jìn)程退出信息*/ waitpid(pid,NULL,0
44、); exit(0); ,管道的局限性,管道的主要局限性正體現(xiàn)在它的特點(diǎn)上: 只支持單向數(shù)據(jù)流; 只能用于具有親緣關(guān)系的進(jìn)程之間; 沒有名字; 管道的緩沖區(qū)是有限的(管道制存在于內(nèi)存中,在管道創(chuàng)建時(shí),為緩沖區(qū)分配一個(gè)頁面大小); 管道所傳送的是無格式字節(jié)流,這就要求管道的讀出方和寫入方必須事先約定好數(shù)據(jù)的格式,比如多少字節(jié)算作一個(gè)消息(或命令、或記錄)等等,FIFO,管道應(yīng)用的一個(gè)重大限制是它沒有名字,因此,只能用于具有親緣關(guān)系的進(jìn)程間通信,在命名管道(namedpipe或FIFO)提出后,該限制得到了克服。 FIFO不同于管道之處在于它提供一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系
45、統(tǒng)中。這樣,即使與FIFO的創(chuàng)建進(jìn)程不存在親緣關(guān)系的進(jìn)程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進(jìn)程以及FIFO的創(chuàng)建進(jìn)程之間),因此,通過FIFO不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。值得注意的是, FIFO 嚴(yán)格遵循先進(jìn)先出(firstinfirstout),對(duì)管道及FIFO的讀總是從開始處返回?cái)?shù)據(jù),對(duì)它們的寫則把數(shù)據(jù)添加到末尾。它們不支持諸如lseek()等文件定位操作。,系統(tǒng)調(diào)用形式: #include #include int mkfifo(const char*pathname,mode_t mode) 該函數(shù)的第一個(gè)參數(shù)是一個(gè)普通的路徑名,也就是創(chuàng)建后FIFO的
46、名字。第二個(gè)參數(shù)與打開普通文件的open()函數(shù)中的mode參數(shù)相同。 一般文件的I/O函數(shù)都可以用于FIFO,如close、read、write等等。,O_RDONLY:讀管道 O_WRONLY:寫管道 O_RDWR:讀寫管道 O_NONBLOCK:非阻塞 O_CREAT: O_EXCL:,FIFO讀規(guī)則,約定:如果一個(gè)進(jìn)程為了從FIFO中讀取數(shù)據(jù)而阻塞打開FIFO,那么稱該進(jìn)程內(nèi)的讀操作為設(shè)置了阻塞標(biāo)志的讀操作。 如果有進(jìn)程寫打開FIFO,且當(dāng)前FIFO內(nèi)沒有數(shù)據(jù),則對(duì)于設(shè)置了阻塞標(biāo)志的讀操作來說,將一直阻塞。對(duì)于沒有設(shè)置阻塞標(biāo)志讀操作來說則返回-1,當(dāng)前errno值為EAGAIN,提醒以
47、后再試。 對(duì)于設(shè)置了阻塞標(biāo)志的讀操作說,造成阻塞的原因有兩種: A.當(dāng)前FIFO內(nèi)有數(shù)據(jù),但有其它進(jìn)程在讀這些數(shù)據(jù); B.另外就是FIFO內(nèi)沒有數(shù)據(jù)。解阻塞的原因則是FIFO中有新的數(shù)據(jù)寫入,不論信寫入數(shù)據(jù)量的大小,也不論讀操作請(qǐng)求多少數(shù)據(jù)量。 讀打開的阻塞標(biāo)志只對(duì)本進(jìn)程第一個(gè)讀操作施加作用,如果本進(jìn)程內(nèi)有多個(gè)讀操作序列,則在第一個(gè)讀操作被喚醒并完成讀操作后,其它將要執(zhí)行的讀操作將不再阻塞,即使在執(zhí)行讀操作時(shí),F(xiàn)IFO中沒有數(shù)據(jù)也一樣(此時(shí),讀操作返回0)。 如果沒有進(jìn)程寫打開FIFO,則設(shè)置了阻塞標(biāo)志的讀操作會(huì)阻塞。,FIFO寫規(guī)則,約定:如果一個(gè)進(jìn)程為了向FIFO中寫入數(shù)據(jù)而阻塞打開FIF
48、O,那么稱該進(jìn)程內(nèi)的寫操作為設(shè)置了阻塞標(biāo)志的寫操作。 對(duì)于設(shè)置了阻塞標(biāo)志的寫操作: 當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時(shí),linux將保證寫入的原子性。如果此時(shí)管道空閑緩沖區(qū)不足以容納要寫入的字節(jié)數(shù),則進(jìn)入睡眠,直到當(dāng)緩沖區(qū)中能夠容納要寫入的字節(jié)數(shù)時(shí),才開始進(jìn)行一次性寫操作。 當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時(shí),linux將不再保證寫入的原子性。FIFO緩沖區(qū)一有空閑區(qū)域,寫進(jìn)程就會(huì)試圖向管道寫入數(shù)據(jù),寫操作在寫完所有請(qǐng)求寫的數(shù)據(jù)后返回。 對(duì)于沒有設(shè)置阻塞標(biāo)志的寫操作: 當(dāng)要寫入的數(shù)據(jù)量大于PIPE_BUF時(shí),linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區(qū)后,寫操作返回
49、。 當(dāng)要寫入的數(shù)據(jù)量不大于PIPE_BUF時(shí),linux將保證寫入的原子性。如果當(dāng)前FIFO空閑緩沖區(qū)能夠容納請(qǐng)求寫入的字節(jié)數(shù),寫完后成功返回;如果當(dāng)前FIFO空閑緩沖區(qū)不能夠容納請(qǐng)求寫入的字節(jié)數(shù),則返回EAGAIN錯(cuò)誤,提醒以后再寫;,/*fifl_read.c*/ #include #include #include #include #include #include #include #define FIFO /tmp/myfifo main(int argc,char* argv) char buf_r100; int fd; int nread; /*創(chuàng)建有名管道,并設(shè)置相應(yīng)的權(quán)限
50、*/ if(mkfifo(FIFO,O_CREAT|O_EXCL)0) ,/*fifo_write.c*/ #include #include #include #include #include #include #include #define FIFO /tmp/myfifo main(int argc,char* argv) /*參數(shù)為即將寫入的字節(jié)數(shù)*/ int fd; char w_buf100; int nwrite; /*打開FIFO管道,并設(shè)置非阻塞標(biāo)志*/ fd=open(FIFO,O_WRONLY|O_NONBLOCK,0); if(fd= -1) printf(open
51、 error; no reading processn); if(argc=1) printf(Please send somethingn); strcpy(w_buf,argv1); /*向管道中寫入字符串*/ if(nwrite=write(fd,w_buf,100)= -1) printf(go into write fifon); if(errno=EAGAIN) printf(The FIFO has not been read yet.Please try latern); else printf(write %s to the FIFOn,w_buf); ,FIFO運(yùn)行結(jié)果,(
52、2)信號(hào)通信,信號(hào)(Signal,亦稱作軟中斷)機(jī)制是在軟件層次上對(duì)中斷機(jī)制的一種模擬。異步進(jìn)程可以通過彼此發(fā)送信號(hào)來實(shí)現(xiàn)簡單通信。系統(tǒng)預(yù)先規(guī)定若干個(gè)不同類型的信號(hào)(如x86平臺(tái)中Linux內(nèi)核設(shè)置了32種信號(hào),而現(xiàn)在的Linux和POSIX.4定義了64種信號(hào)),各表示發(fā)生了不同的事件,每個(gè)信號(hào)對(duì)應(yīng)一個(gè)編號(hào)。運(yùn)行進(jìn)程當(dāng)遇到相應(yīng)事件或出現(xiàn)特定要求時(shí)(如進(jìn)程終止或運(yùn)行中出現(xiàn)某些錯(cuò)誤非法指令、地址越界等),就把一個(gè)信號(hào)寫到相應(yīng)進(jìn)程task_struct結(jié)構(gòu)的Signal位圖(表示信號(hào)的整數(shù))中。接收信號(hào)的進(jìn)程在運(yùn)行過程中要檢測自身是否收到了信號(hào),如果已收到信號(hào),則轉(zhuǎn)去執(zhí)行預(yù)先規(guī)定好的信號(hào)處理程序。
53、處理之后,再返回原先正在執(zhí)行的程序。 信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。它可以在任何時(shí)候發(fā)給某一進(jìn)程,而無需知道該進(jìn)程的狀態(tài)。如果該進(jìn)程當(dāng)前并未處于執(zhí)行態(tài),則該信號(hào)就由內(nèi)核保存起來,直到該進(jìn)程恢復(fù)執(zhí)行再傳遞給它為止;如果一個(gè)信號(hào)被進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程。,信號(hào)的三個(gè)階段,一個(gè)完整的信號(hào)生命周期可以分為 3 個(gè)重要階段,這 3 個(gè)階段由 4 個(gè)重要事件來刻畫的:信號(hào)產(chǎn)生、信號(hào)在進(jìn)程中注冊(cè)、信號(hào)在進(jìn)程中注銷、執(zhí)行信號(hào)處理函數(shù)。,信號(hào)的處理,用戶進(jìn)程對(duì)信號(hào)的響應(yīng)可以有3種方式。
54、忽略信號(hào),即對(duì)信號(hào)不做任何處理,但是有兩個(gè)信號(hào)不能忽略,即 SIGKILL 及SIGSTOP。 捕捉信號(hào),定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的處理函數(shù)。 執(zhí)行缺省操作,Linux對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作。,信號(hào)的分類,Kill,raise,alarm和pause,函數(shù)調(diào)用形式: #include int kill(pid_t pid,int sig); int raise(int sig); unisigned int alarm(unsigned int seconds); int pause(void); 作用:kill系統(tǒng)調(diào)用負(fù)責(zé)向進(jìn)程發(fā)送信號(hào)sig; raise系統(tǒng)調(diào)用向自己發(fā)
55、送一個(gè)sig信號(hào),可以用kill函數(shù)來實(shí)現(xiàn)這個(gè)功能的;alarm函數(shù)和時(shí)間有點(diǎn)關(guān)系了,這個(gè)函數(shù)可以在seconds秒后向自己發(fā)送一個(gè)SIGALRM信號(hào);pause用于將調(diào)用進(jìn)程掛起直到捕捉到信號(hào)為止。 參數(shù): 如果pid是正數(shù),那么信號(hào)sig被發(fā)送到進(jìn)程pid. 如果pid等于0,那么信號(hào)sig被發(fā)送到和pid進(jìn)程在同一個(gè)進(jìn)程組的進(jìn)程 如果pid等于-1,那么信號(hào)發(fā)給所有的進(jìn)程表中的進(jìn)程,除了最大的哪個(gè)進(jìn)程號(hào).,/*kill.c*/ #include #include #include #include #include int main() pid_t pid; int ret; /*創(chuàng)建一
56、子進(jìn)程*/ if(pid=fork()0) perror(fork); exit(1); if(pid = 0) /*在子進(jìn)程中使用raise函數(shù)發(fā)出SIGSTOP信號(hào)*/ printf(the child is go into stopn); raise(SIGSTOP); printf(the child is sleepn); exit(0); else /*在父進(jìn)程中收集子進(jìn)程發(fā)出的信號(hào),并調(diào)用kill函數(shù)進(jìn)行相應(yīng)的操作*/ sleep(3); printf(pid=%dn,pid); if(waitpid(pid,NULL,WNOHANG)=0) if(ret=kill(pid,SI
57、GKILL)=0) printf(kill %dn,pid); else perror(kill); ,Kill運(yùn)行結(jié)果,信號(hào)的處理,從前面的信號(hào)概述中我們可以看到,特定的信號(hào)是與一定的進(jìn)程相聯(lián)系的。也就是說,一個(gè)進(jìn)程可以決定在該進(jìn)程中需要對(duì)哪些信號(hào)進(jìn)行什么樣的處理。例如,一個(gè)進(jìn)程可以選擇忽略某些信號(hào)而只處理其他一些信號(hào),另外,一個(gè)進(jìn)程還可以選擇如何處理信號(hào)??傊?,這些都是與特定的進(jìn)程相聯(lián)系的。因此,首先就要建立其信號(hào)與進(jìn)程之間的對(duì)應(yīng)關(guān)系,這就是信號(hào)的處理。 信號(hào)處理的主要方法有兩種,一種是使用簡單的 signal 函數(shù),另一種是使用信號(hào)集函數(shù)組。,signal(),#include void
58、 (*signal(int signum, void (*handler)(int)(int) 參數(shù):signum:指定信號(hào) Handler:處理函數(shù)句柄 SIG_IGN:忽略該信號(hào) SIG_DFL:采用系統(tǒng)默認(rèn)方式處理信號(hào) 自定義的信號(hào)處理函數(shù)指針 函數(shù)返回值 :成功時(shí)返回以前的信號(hào)處理配置 ,出錯(cuò)時(shí)返回-1 。,/*mysignal.c*/ #include #include #include /*自定義信號(hào)處理函數(shù)*/ void my_func(int sign_no) if(sign_no=SIGINT) printf(I have get SIGINTn); else if(sign
59、_no=SIGQUIT) printf(I have get SIGQUITn); int main() printf(Waiting for signal SIGINT or SIGQUIT n ); /*發(fā)出相應(yīng)的信號(hào),并跳轉(zhuǎn)到信號(hào)處理函數(shù)處*/ signal(SIGINT, my_func); signal(SIGQUIT, my_func); pause(); exit(0); ,Signal運(yùn)行,(3)共享內(nèi)存,共享內(nèi)存可以說是最有用的進(jìn)程間通信方式,也是最快的IPC形式。兩個(gè)不同進(jìn)程A、B共享內(nèi)存的意思是,同一塊物理內(nèi)存被映射到進(jìn)程A、B各自的進(jìn)程地址空間。進(jìn)程A可以即時(shí)看到進(jìn)程B對(duì)共享內(nèi)存中數(shù)據(jù)的更新,反之亦然。 由于多個(gè)進(jìn)程共享同一塊內(nèi)存區(qū)域,必然需要某種同步機(jī)制,互斥鎖和信號(hào)量都可以。,共享內(nèi)存的好處,采用共享內(nèi)存通信的一個(gè)顯而易見的好處是效率高,因?yàn)檫M(jìn)程可以直接讀寫內(nèi)存,而不需要任何
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 福建護(hù)坡加固施工方案
- 房屋買賣合同預(yù)售合同
- 中華傳統(tǒng)美文鑒賞教學(xué)方法:古詩解析與創(chuàng)作訓(xùn)練
- 屋面漏水導(dǎo)流施工方案
- 阜陽別墅木屋施工方案
- 接戶線施工方案
- 塔吊安裝專項(xiàng)施工方案
- 漢口閣樓安裝施工方案
- 鍋爐除渣干式排渣施工方案
- 年產(chǎn)12000噸聚羧酸高性能減水劑復(fù)配液及3000噸水泥助磨劑復(fù)配液項(xiàng)目環(huán)評(píng)報(bào)告表
- 2024年全國英語競賽《B類英語專業(yè)》初賽試題真題及答案
- 小學(xué)生中國舞課件大全
- 2025年南京信息職業(yè)技術(shù)學(xué)院單招職業(yè)技能測試題庫完整
- 《Spring框架》教學(xué)課件
- 2025年中考英語閱讀訓(xùn)練:熱點(diǎn)-電影《哪吒》(含答案)
- 2025年中考英語時(shí)文閱讀 6篇有關(guān)電影哪吒2和 DeepSeek的英語閱讀(含答案)
- 客戶溝通技巧與客戶投訴處理培訓(xùn)課件
- 完整版臨時(shí)用水用電施工方案
- 江蘇省南通市2025屆高三第一次調(diào)研測試數(shù)學(xué)試題(南通一模)(含答案)
- 【課件】進(jìn)出口貨物報(bào)關(guān)單填制
- Codesys培訓(xùn)課件教學(xué)課件
評(píng)論
0/150
提交評(píng)論