進程與進程管理 | 進程通信
進程通信的概念:
進程通信是指進程之間直接以較高的效率傳遞較多數據的信息交互方式。
低級通信類型:
前面所講到的信號量通信方式
高級通信類型
- 共享存儲器系統通信(Shared-Memory System)
- 管道(pipe)通信
- 消息傳遞系統通信(Message passing System)
共享存儲器系統通信
通過共享某些數據結構或共享存儲器實現進程之間的信息交換。
- 通信過程: linux中相應系統調用
- 申請共享存儲分區; shmget()
- 將共享存儲分區映射到本進程地址空間中; shmat()
- 進行數據讀寫;
- 釋放共享存儲分區; shmdt()
- 刪除共享存儲分區: shmctl()
- 共享存儲器系統通信方式的特點:
- 最大的特點是沒有中間環節,直接把共享內存映射到不同進程的虛擬地址空間中,進程可直接進行訪問,通信直接快速。
- 該通信機制沒有提供進程同步機制。
代碼描述:
#include<stdio.h>#include<sys/types.h>#include<sys/msg.h>#include<sys/ipc.h>#include<unistd.h>#define SHMKEY 75int shmid,i;int *addr;// 發送進程void CLIENT() { int i; shmid = shmget(SHMKEY,1024,0777); addr = shmat(shmid,0,0); for(i=9;i>=0;i--) { while(*addr != -1); //是否已讀取 printf("(client)sent"); *addr=i; printf("%d
",*addr); sleep(1); }}// 接收進程void SERVER() { shmid = shmget(SHMKEY,1024,0777|IPC_CREAT); addr = shmat(shmid,0,0);//附接到用戶的虛地址空間 do{ *addr=-1; while(*addr == -1);//client是否已經寫入 printf("(server)received%d
",*addr); sleep(1); }while(*addr); shmctl(shmid,IPC_RMID,0);}main(){ int p1,p2; p1=fork(); if(p1==0) SERVER(); else{ p2=fork(); if(p2==0) CLIENT(); } wait(0); wait(0);}
管道通信
管道通信概念
- 管道:用於連接一個讀進程和一個寫進程,以實現它們之間通信的共享文件(pipe文件,又稱為FIFO文件)
- FIFO文件的讀出和寫入 :嚴格遵循先進先出 ,不支持文件定位操作。
兩種實現機制
(1)無名管道:
int pipe(int fd[2])
其中: fd[1]為寫入端, fd[0]為讀出端。
用於父子或兄弟進程間通信。
(由於磁碟上的任何一個文件都需要一個文件名,所以在無名管道中建立的共享文件並沒有保存到磁碟上,而是在高速緩衝中建立一個緩存文件。)
(2)有名管道:
int mkfifo(const char * pathname, mode_t mode)
用於任意進程間通信(又稱FIFO 通信)
普通文件在磁碟上除了有描述性的數據結構,同時還有相應的磁碟空間來存放內容。而管道文件只在通信的時候需要存儲空間,在平時只有一個描述數據結構存放在磁碟上。比如說索引節點。
有名管道文件一旦創建就會永遠的存放在磁碟上,除非進程使用顯示的方式刪除這個文件。
管道通信應注意的問題
為了協調雙方的通信,管道通信機制必須提供以下三方面的協調能力:
- 互斥。一個進程正在對pipe進行讀/寫操作時,另一進程必須等待。
- 同步。當寫(輸入)進程把一定數量的數據寫入pipe後,便去睡眠等待,直到讀(輸出)進程取走數據將其喚醒;當讀進程讀一空pipe,也應睡眠等待,直至寫進程將數據寫入管道,才將其喚醒。
- 對方是否存在。只有確定對方已存在時,才能進行管道通信,否則會造成因對方不存在而無限期等待。
無名管道應用舉例
編寫一程序,建立一個管道。同時,父進程生成了進程P1和P2,這兩個子進程分別向管道中寫入各自的字元串,父進程讀出它們。
代碼描述:
// lockf:用於鎖定文件的某些段或整個文件// 頭文件:#include<unistd.h>// 參數定義:int lockf(files,function,size)// int files,function:long size// function:1鎖定,0解鎖// Size:0,表示從文件的當前位置到文件尾#include <stdio.h>#include<unistd.h>main( ){ int i, r, p1, p2,fd[2]; char buf[50], s[50]; pipe(fd); p1=fork(); if( p1 == 0 ) { lockf( fd[1], 1, 0); sprintf(buf,「child process1 is sending n」); printf( "child process1!
"); write( fd[1], buf, 50 ); sleep( 5 ); lockf( fd[1], 0, 0 ); exit(0); } p2 = fork( ); if( p2 == 0 ) { lockf( fd[1], 1, 0 ); sprintf(buf,"child process2 is sending!
"); printf( "child process2!
"); write( fd[1], buf, 50 ); sleep( 5 ); lockf( fd[1], 0, 0 ); exit( 0 ); } else { wait(0); if((r = read( fd[0], s, 50 )) == -1 ) printf( "cant read pipe
"); else printf( "%s
", s ); wait(0); if((r = read( fd[0], s, 50)) == -1) printf( "cant read pipe
"); else printf( "%s
", s ); exit(0); }}
消息傳遞系統通信
概念:
進程間的數據交換是以消息(message,在計算機網路中又稱報文)為單位。程序員直接利用系統提供的一組通訊命令(原語)來實現通訊。
在消息通信中,接收方和發送方之間有明確的協議和消息格式 。
消息格式:
- 消息頭:存放消息傳輸時所需的控制信息。
- 消息類型:
- 定長消息;
- 變長消息。
消息傳遞系統實現類型:
(1)消息緩衝隊列機制:
發送進程直接將消息發送給接收進程,並將它掛在接收進程的消息緩衝隊列上。接收進程從消息緩衝隊列中取得消息。
(2)信箱通信方式:
發送進程將消息發送到某個中間實體(一般稱為信箱)中,接收進程從中取得消息,所以稱為信箱通訊方式,相應地系統稱為電子郵件系統。
信箱通信中,需要定義信箱結構,還包括消息發送 和接收功能模塊,提供發送原語和接收原語。
信箱頭:郵箱名稱、郵箱大小、擁有該郵箱的進程名
信箱體:存放發送進程發送到信箱中的郵件。
使用郵箱的時候應該滿足:
- 發送進程發送消息時,郵箱中至少要有一個空格能存放該消息
- 接收進程接收消息時,郵箱中至少有一個消息存在
消息緩衝隊列通信機制的實現:
其數據結構的設置如下:
- 消息緩衝區
struct mesg_buffer { char *sender; // 發送者的描述符 char *text; // 指向消息正文的指針 int size; // 消息的長度 struct mesg_buffer *next; // 下一個消息緩衝區}buffer;
- 消息緩衝隊列
- 空白消息緩衝隊列; freebuff_mutex; freebuf_sm
- 接收進程的消息隊列
- PCB中與通信有關的數據項:
- mq: 消息隊列隊首指針;
- mutex:消息隊列互斥信號量;
- sm:消息隊列同步信號量
發送原語:
發送原語的工作如下:
其演算法描述如下:
procedure send(receiver,a) // 接收進程的描述符和要發送的消息的存放位置{ i= getbuf(); // 申請一個空白的消息緩衝區 : // P(freebuf_sm); 判斷空白的消息隊列中是否有空白的消息緩衝區 // P(freebuf_mutex); // get a freebuf; 獲得空白消息隊列的使用權 // V(freebuf_mutex); 釋放消息緩衝隊列 // 將自己的與消息相關的信息複製到消息緩衝隊列中 i.sender=a.sender; i.size=a.size; i.text=a.text; i.next=Null; j=getpcb(receiver); // 找到接收進程的 PCB P(j.mutex); // 獲得接收進程的使用權 insert(j.mq, i); // 將消息緩衝區掛到接收進程的消息隊列中 V(j.mutex); V(j.sm) }
接收原語:
演算法描述:
procedure receive(b){ j= receiver』s internal name; P(j.sm); // 接收隊列中有消息存放 P(j.mutex); // 當前沒有別的互斥操作 remove(j.mq,i); // 從接收隊列中取出一個消息 V(j.mutex); b.sender=i.sender; b.size=i.size; b.text=i.text; putbuf(i); // 釋放消息緩衝區 // P(freebuf_mutex); 獲得空白消息緩衝隊列的使用權 // put a freebuf 把空白消息緩衝區掛到空白消息隊列中 // V(freebuf_mutex); 釋放空白消息緩衝隊列 // V(freebuf_sm); }
推薦閱讀:
※windows為何不收購everything等第三方優秀的工具集成在自己的系統當中以改進自己某方面系統功能的弱勢?
※win10專業版系統下載
※遊戲開發與程序設計知識總結04——操作系統
※重裝系統後出現流氓軟體
※超級強大的系統清理工具CCleaner
TAG:操作系統 |