?? 多進程編程的相關知識總結(一).txt
字號:
int v;
/*取得或創(chuàng)建一個共享數(shù)據(jù)空間(系統(tǒng)特殊文件),名字為
/tmp/area1,長度為640,用戶訪問權限為0777*/
area1=sdget("/tmp/area1",SD_WRITE|SD_CREAT,640,0777);
if ((int)area1==-1) {
printf("get share data segment area1 failed\n");
exit(1);
}
/*取得共享數(shù)據(jù)段area1的版本號*/
v=sdgetv(area1);
/*申請訪問共享數(shù)據(jù)段area1,若已有進程在訪問該段則本進程掛
*起,否則進入訪問并將該數(shù)據(jù)段加寫鎖*/
sdenter(area1,SD_WRITE);
/*對共享數(shù)據(jù)段訪問,寫10個a*/
strcpy(area1,"aaaaaaaaaa");
/*申請解除訪問權限,若已有進程申請訪問則激活該進程*/
sdleave(area1);
/*進程處理過程*/
/*等待取共享數(shù)據(jù)段area1的版本號*/
sdwaitv(area1,v);
/*重新申請訪問共享數(shù)據(jù)段area1*/
sdenter(area1,SD_WRITE);
/*讀取共享數(shù)據(jù)段中的數(shù)據(jù)*/
memcpy(buf,area1,20);
/*申請解除訪問權限,若已有進程申請訪問則激活該進程*/
sdleave(area1);
printf("the data now in area1 is [%s]\n",buf);
31.getenv()
功能:取得指定環(huán)境變量值.
語法:#include <unistd.h>
#include <stdlib.h.
char *getenv(name)
char *name;
說明:本系統(tǒng)調用檢查環(huán)境字符串(格式如name=value),并在找到有指
定名字的環(huán)境值后,返回指向value字符串的指針.否則返回空指
針.
返回值:如前述.
例子:char * value;
value=getenv("HOME");
printf("HOME = [%s]\n",value);
/*將打印出HOME環(huán)境變量的值*/
32.putenv()
功能:修改或增加環(huán)境值.
語法:#include <stdlib.h>
int putenv(string)
char *string;
說明:參數(shù)string指向一個字符串,格式如下:
name=value
本系統(tǒng)調用將環(huán)境變量name等于值value,修改或增加一個環(huán)境變
量,字符串string成為環(huán)境的一部分.
返回值:若putenv()不能取得合適的內存空間則返回非0值,否則返回0.
例子:/*父進程處理*/
putenv("HOME=/home/abcdef");
putenv("PATH=/bin");
if (fork()>0)
exit(0); /*父進程退出運行*/
/*子進程處理*/
setpgrp();
/*父進程設置的環(huán)境變量已傳到子進程*/
char * value1;
value1=getenv("HOME");
value2=getenv("PATH");
printf("HOME=[%s],PATH=[%s]\n",value1,value2);
/*將打印出"HOME=/home/abcdef"和"PATH=/bin"*/
三.多進程編程技巧
1.主要程序結構
(1)事件主控方式
若是應用程序屬于事務處理方式,則在主函數(shù)中設計為監(jiān)控事件發(fā)生,
當事件發(fā)生時,可以生成一個新的進程來處理該事務,事務處理完成后就
可以讓子進程退出系統(tǒng).這種處理方式一般不要消息傳遞.
(2)信息協(xié)調方式
若是應用程序需要由多個進程協(xié)調處理完成,則可以生成這些進程,
通過消息在進程間的傳遞,使各個進程能相互協(xié)調,共同完成事務.這種處
理方式一般是用fork()生成幾個進程后,用exec()調用其它程序文件,使
得不同的程序同時在系統(tǒng)內運行.然后通過IPC機制傳送消息,使各個程序
能協(xié)調運行.
2.選擇主體分叉點
(1)事件初始產生
對應于事件主控方式的程序結構.關鍵點在于以何種方式選擇事件的
初始發(fā)生點,如網(wǎng)絡程序給出的建鏈信息.主控程序在收到該消息后就認
為是一個事件開始,則可以產生一個子進程處理后面的事務:接收交易信
息,事務處理,發(fā)送返回交易信息,關閉鏈接等,完成后將子進程退出系統(tǒng).
(2)主程序自主產生
對應于信息協(xié)調方式的程序結構.主控程序只負責生成幾個子進程,各
個子進程分別調用exec()將不同的執(zhí)行文件調入內存運行,主控程序在生
成所有的子進程后即可退出系統(tǒng),將子進程留在內存中運行.
3.進程間關系處理
(1)父子進程關系
. 進程組處理
進程組的概念是這樣的,當系統(tǒng)啟動時,第一個進程是init,其進程
組號等于進程號,由它產生的所有子進程的進程組號也相同,子進程
的子進程也繼承該進程組號,這樣,由init所生成的所有子進程都屬
于同一個進程組.但是,同一個進程組的父子進程可能在信號上有相
互通訊,若父進程先于子進程退出系統(tǒng),則子進程會成為一個孤兒進
程,可能變成僵死進程.從而使該子進程在其不"愿意"的情況下退出
運行.為解決這個問題,子進程可以自己組成一個新的進程組,即調
用setpgrp()與原進程組脫離關系,產生一個新的進程組,進程組號
與它的進程號相同.這樣,父進程退出運行后就不會影響子進程的當
前運行.
. 子進程信號處理
但是,單做上述處理還不能解決另一個困難,即子進程在退出運行
時,找不到其父進程(父進程已退出,子進程的父進程號改為1).發(fā)送
子進程退出信號后沒有父進程做出響應處理,該子進程就不可能完
全退出運行,可能進入僵死狀態(tài).所以父進程在產生子進程前最好屏
蔽子進程返回信號的處理,生成子進程,在父進程退出運行后,子進
程返回則其進程返回信號的處理會由系統(tǒng)給出缺省處理,子進程就
可以正常退出.
(2)兄弟進程關系
. 交換進程號
對于信息協(xié)調方式的程序來說,各兄弟進程間十分需要相互了解進
程號,以便于信號處理機制.比較合理的方法是父進程生成一個共享
內存的空間,每個子進程都在啟動時在共享內存中設置自己的進程
號.這樣,當一個子進程要向另一個子進程發(fā)送信號或是因為其他原
因需要知道另一個子進程號時,就可以在共享內存中訪問得到所需
要的進程號.
4.進程間通訊處理
(1)共享內存需要鎖機制
由于共享內存在設計時沒有處理鎖機制,故當有多個進程在訪問共享
內存時就會產生問題.如:一個進程修改一個共享內存單元,另一個進程在
讀該共享內存單元時可能有第三個進程立即修改該單元,從而會影響程序
的正確性.同時還有分時系統(tǒng)對各進程是分時間片處理的,可能會引起不
同的正確性問題.按操作系統(tǒng)的運作方式,則有讀鎖和寫鎖來保證數(shù)據(jù)的
一致性.所以沒有鎖機制的共享內存,必須和信號量一起使用,才能保證共
享內存的正確操作.
(2)消息隊列需要關鍵值
消息隊列的操作在進程取得消息隊列的訪問權限后就必須通過關鍵
值來讀消息隊列中的相同關鍵值的消息,寫消息時帶入消息關鍵值.這樣
可以通過不同的關鍵值區(qū)分不同的交易,使得在同一個消息隊列可以供多
種消息同時使用而不沖突.若讀消息隊列使用關鍵值0則讀取消息隊列中
第一個消息,不論其關鍵值如何.
(3)信號需要信號處理函數(shù)設置和再設置
在用戶進程需要對某個中斷做自己定義的處理時,可以自己定義中斷
處理函數(shù),并設置中斷處理函數(shù)與該中斷相關聯(lián).這樣,用戶進程在收到該
中斷后,即調用用戶定義的函數(shù),處理完成后用戶進程從被中斷處繼續(xù)運
行(若用戶定義的中斷函數(shù)沒有長跳函數(shù)或退出運行等會改變運行指令地
址的系統(tǒng)調用).在中斷信號被處理后,該中斷的處理函數(shù)會恢復成上次缺
省處理函數(shù)而不是保持用戶定義函數(shù),故在用戶定義的中斷處理函數(shù)中一
般都再定義該中斷和函數(shù)自己的關聯(lián).
(4)IPC的權限設置
在消息隊列,共享內存和信號量的訪問時有用戶訪問權限設置,類同
于文件的訪問權限的設置如(777表示rwxrwxrwx),用命令ipcs即可看到在
系統(tǒng)中生成的消息隊列,共享內存和信號量的訪問權限.其意義也類似于
文件訪問權限.只是執(zhí)行位無效.
在有名管道和文件方式共享內存中以系統(tǒng)文件的方式定義了用戶的
訪問權限.用命令ls -l可以看到它們以系統(tǒng)文件方式存在并具有訪問權
限值,并可以看到有名管道的文件類型為p,文件方式共享內存的文件類型
為s.
(5)信號中斷對系統(tǒng)調用一級有效
系統(tǒng)在設計系統(tǒng)調用時就考慮了中斷處理問題.當進程運行到一個系
統(tǒng)調用時發(fā)生了中斷,則進程進入該中斷處理,處理完成后,進程會跳過該
系統(tǒng)調用而進入下一條程序指令.
應該注意的是中斷發(fā)生在系統(tǒng)調用一級而不是子程序或函數(shù)一級.比
如一個程序在一個子程序被調用前設置了超時中斷,并在子程序中收到超
時中斷,系統(tǒng)在處理完超時中斷后接著處理該子程序被中斷的系統(tǒng)調用之
后的指令,而不是從調用該子程序名指令的后一條指令繼續(xù)處理.
(6)各種IPC方式的特點
. 消息隊列:
通過消息隊列key值定義和生成消息隊列.
任何進程只要有訪問權限并知道key即可訪問消息隊列.
消息隊列為內存塊方式數(shù)據(jù)段.
消息隊列中的消息元素長度可為系統(tǒng)參數(shù)限制內的任何長度.
消息元素由消息類型分類,其訪問方式為按類型訪問.
在一次讀寫操作前都必須取得消息隊列標識符,即訪問權.訪問后即
脫離訪問關系.
消息隊列中的某條消息被讀后即從隊列中刪除.
消息隊列的訪問具備鎖機制處理,即一個進程在訪問時另一個進程
不能訪問.
操作時要注意系統(tǒng)資源和效率.
在權限允許時,消息隊列的信息傳遞是雙向的.
. 共享內存
通過共享內存key值定義和生成共享內存.
任何進程只要有訪問權限并知道key即可訪問共享內存.
共享內存為內存塊方式的數(shù)據(jù)段.
共享內存中的數(shù)據(jù)長度可為系統(tǒng)參數(shù)限制內的任何長度.
共享內存的訪問同數(shù)組的訪問方式相同.
在取得共享內存標識符將共享內存與進程數(shù)據(jù)段聯(lián)接后即可開始對
之進行讀寫操作,在所有操作完成之后再做共享內存和進程數(shù)據(jù)
段脫離操作,才完成全部共享內存訪問過程.
共享內存中的數(shù)據(jù)不會因數(shù)據(jù)被進程讀取后消失.
共享內存的訪問不具備鎖機制處理,即多個進程可能同時訪問同一
個共享內存的同一個數(shù)據(jù)單元.
共享內存的使用最好和信號量一起操作,以具備鎖機制,保證數(shù)據(jù)的
一致.
在權限允許時,共享內存的信息傳遞是雙向的.
. 信號量
用于生成鎖機制,避免發(fā)生數(shù)據(jù)不一致.
沒有其他的數(shù)據(jù)信息.
不需要有父子關系或兄弟關系.
. 信號
信號由系統(tǒng)進行定義.
信號的發(fā)送只要有權限即可進行.
信號是一個事件發(fā)生的信息標志,不帶有其它信息.
信號不具備數(shù)據(jù)塊.
信號的處理可由用戶自己定義.
信號可能由用戶進程,操作系統(tǒng)(軟件或硬件原因)等發(fā)出.
有一些信號是不可被屏蔽的.
信號中斷的是系統(tǒng)調用級的函數(shù).
信號的信息傳遞是單向的.
. 管道
做為系統(tǒng)的特殊設備文件,可以是內存方式的,也可以是外存方式的.
管道的傳輸一般是單向的,即一個管道一向,若兩個進程要做雙向傳
輸則需要2個管道.管道生成時即有兩端,一端為讀,一端為寫,兩個
進程要協(xié)調好,一個進程從讀方讀,另一個進程向寫方寫.
管道的讀寫使用流設備的讀寫函數(shù),即:read(),write.
管道的傳輸方式為FIFO,流方式的.不象消息隊列可以按類型讀取.
* 有名管道
一般為系統(tǒng)特殊文件方式,使用的進程之間不一定要有父子關系
或兄弟關系.
* 無名管道
一般為內存方式,使用的進程之間一定要有父子關系或兄弟關系.
. 文件
文件是最簡單的進程間通訊方式,使用外部存貯器為中介.
操作麻煩,定位困難.
保密程度低.
容易出現(xiàn)數(shù)據(jù)不一致問題.
占用硬盤空間.
只要有權限并知道文件名,任何進程都可對之操作.
* 特殊處理
為避免出現(xiàn)保密問題,在打開文件,取得文件描述符后,調用
unlink()將硬盤上的文件路徑名刪除,則硬盤上就沒有文件拷貝
了.但在進程中該文件描述符是打開的,由該進程生成的子進程中
該文件描述符也是打開的,就可以利用系統(tǒng)提供的文件緩沖區(qū)做
進程間通訊,代價是進程間必須有父子關系或兄弟關系.
. 環(huán)境變量
信息的傳送一般是單向的,即由父進程向子進程傳送.
保密性較好.
雙方必須約定環(huán)境變量名.
只占用本進程和子進程的環(huán)境變量區(qū).
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -