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