小河學習日記 --進程間通信

一。基本概念
什麼是進程間通信:就是多個進程在運行時傳遞數據
爲什麼需要進程間通信:進程是一個獨立的資源單位,基本可以自給自足(能解決一個獨立的問題)。但很多問題卻不是獨立的,所以進程也需要相互合作,這時就需要進程間通信了。
進程間的通信方式:
傳統:管道
簡單:命令行參數,環境變量、信號、文件
xsi:消息隊列,共享內存、信號量
網絡:
二、傳統的進程間通信-管道
管道是UNIX系統最古老的進程間通信方式(基本不再使用),歷史上的管道通常是半雙工(只允許單向數據流動),現在的系統大都可以全雙工,數據可以雙向流動。
1、有名管道(創建實體文件)
命令:mkfifo
函數:int mkfifo(const char *pathname, mode_t mode);
功能:創建管道文件
pathname:文件路徑
mode:權限
返回值:成功返回0,失敗返回-1。

	編程模型:
	進程A					進程B
	創建管道(mkfifo)		...
	打開管道(open)			打開管道
	讀/寫數據	(read/write)	讀/寫數據
	關閉管道(close)			關閉管道
	刪除管道(unlink)			...

2、無名管道(用於通過fork創建的父子進程之間通信)
int pipe(int pipefd[2]);
功能:創建無名管道
pipefd:用來存儲內核返回的文件描述符
pipefd[0] 用於讀操作
pipefd[1] 用於寫操作
編程模型同上

三、XSI進程間通信
X/open組織爲UNIX系統設計一套進程間通信機制,有共享內存、消息隊列、信號量。
1、IPC標識
內核會爲每個進程間通信維護一個IPC對象(XSI對象)。
該對象通過一個非負整數來引用(類似於文件描述符)。
與文件描述符不同的是,每用一個IPC對象標識符就持續+1,達到最大值時再從零開始。
IPC標識需要程序員自己創建(類似於創建文件)。
2、IPC鍵值
創建IPC鍵值的依據(類似創建文件的文件名),也是一個非負整數。
1、自定義(不建議,可能會衝突)。
2、自動生成(項目路徑,項目編號)。
key_t ftok(const char *pathname, int proj_id);
注意:項目路徑一定要是有效路徑,生成IPC鍵依靠的是路徑而不是字符串。
3、IPC對象的創建用到的宏
IPC_PRIVATE 創建IPC對象時永遠創建成功。
IPC_CREAT 對象存在則獲取,不存在則創建。
IPC_EXCL 如果對象已經創建,則創建失敗。
4、IPC對象銷燬/控制用到的宏
IPC_STAT 獲取IPC對象的屬性
IPC_SET 設置IPC對象的屬性
IPC_RMID 刪除IPC對象

四、共享內存
共享內存就是內核中開闢一塊由IPC對象管理內存,進程A和進程B都用自己的虛擬地址與它進程映射,這樣他就共享了同一塊內存,然後就可以通信了。
特點:
1、不需要複製信息,是最快的一種進程間通信機制。
2、需要考慮同步問題(必須藉助其它的機制,如信號)。
編程模型:
進程A 進程B
生成IPC鍵值 ftok 生成IPC鍵 ftok
創建共享內存 shmget 獲取共享內存 shmget
映射共享內存 shmat 映射共享內存 shmat
使用共享內存 *ptr 使用共享內存 *ptr
取消映射 shmdt 取消映射 shmdt
刪除共享內存 shmctl …

int shmget(key_t key, size_t size, int shmflg)
功能:創建/獲取共享內存
key:IPC鍵,由ftok函數生成
size:共享內存的大小,最好是4096的整數倍,獲取共享內存時,此值無效。
shmflg:
	0 獲取共享內存
	IPC_CREAT 創建
	IPC_EXCL 如果存在則創建失敗
返回值:成功返回共享內存標識(IPC標識),失敗返回-1。

void* shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享內存
shmid:共享內存標識符,shmget函數的返回值。
shmaddr:進程提供的虛擬地址,與內核中的內存映射用的,也可以是NULL(內核會自動選擇一個地址映射)。
shmflg:
	0 自動分配
	SHM_RDONLY 只讀權限
	SHM_RND 當shmaddr不爲空時shmaddr向下取整頁。
返回值:映射成功後的虛擬地址。

int shmdt(const void *shmaddr);
功能:取消虛擬地址與共享內存的映射
shmaddr:被映射過的虛擬地址

int shmctl(int shmid, int cmd, struct shmid_ds* buf);
功能:刪除共享內存,獲取/設置共享內存的屬性
shmid:共享內存標識符shmget的返回值
cmd:
	IPC_STAT 獲取共享內存的屬性
	IPC_SET 設置共享內存的的屬性
	IPC_RMID 刪除IPC共享內存
	
struct shmid_ds {
	struct ipc_perm shm_perm;	// 內存所有者及權限
	size_t          shm_segsz;  // 內存的大小
	time_t          shm_atime;  // 最後的映射時間
	time_t          shm_dtime;  // 最後的取消映射時間
	time_t          shm_ctime;  // 最後修改時間
	pid_t           shm_cpid;   // 創建者進程ID
	pid_t           shm_lpid;   // 最後映射/取消映射的進程ID
	shmatt_t 		shm_nattch; // 映射的次數

struct ipc_perm {
	key_t          __key;	// IPC鍵值
	uid_t          uid;		// 有效用戶ID 
	gid_t          gid;     // 有效組ID
	uid_t          cuid;    // 創建者的用戶ID
	gid_t          cgid;    // 創建者組ID
	unsigned short mode;    // 權限
	unsigned short __seq; 	// IPC標識

五、消息隊列
消息隊列就是由內核負責管理的一個管道,可以按順序發送消息包(消息類型+消息內容),可以全雙工工作,可以不按消息的順序接收消息。

int msgget(key_t key, int msgflg);
功能:創建/獲取消息隊列
key:IPC鍵值,由ftok函數自動生成
msgflg:
	0 獲取消息隊列
	IPC_CREAT 創建消息隊列
	IPC_EXCL 如果存在則創建失敗
返回值:消息隊列標識
	
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息隊列發送消息
msqid:消息隊列標識,msgget函數的返回值
msgp:結構指針
	 struct msgbuf {
           long mtype; 		//消息類型
           char mtext[n]; 	//消息內容  
     };
msgsz:消息的長度,不包括消息類型,sizeof(msgbuf)-4。
msgflg:
	0 阻塞,當消息隊列滿時,等待。
	IPC_NOWAIT 不阻塞,當消息隊列滿時,不等待。
返回值:成功發送返回0,失敗返回-1。
	
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:從消息隊列中按類型獲取消息
msqid:消息隊列標識,msgget函數的返回值
msgp:
	struct msgbuf {
           long mtype; 		//消息類型
           char mtext[n]; 	//消息內容  
     };
msgsz:要接收一消息的長度,可以長一些。
msgtyp:要接收的消息類型
	0 接收任意類型的消息(接收隊列中第一個消息)。
	>0 只接收msgtyp類型的消息
	<0 接收消息隊列中小於等於msgtyp絕對值的消息,取小的那個。
msgflg:
	0 阻塞,消息隊列中是否有對應類型的消息,沒有則等待。
	1 不阻塞,消息隊列中沒有對應類型的消息,則返回。
	----------------------------------------
	MSG_NOERROR:
		消息類型正確,而消息的實際長度大於msgsz,則不接收消息並返回-1。
		如果msgflg帶MSG_NOERROR標誌,則把多餘的消息截取,成功接收。
	IPC_NOWAIT:如果消息隊列沒有要接收的消息,則不等待,返回-1。
	MSG_EXCEPT:接收消息隊列中第一個消息類型不是msgtyp的消息,編譯時添加-D_GNU_SOURCE參數。
	
返回值:成功接收到消息的字節數

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:刪除消息隊列,設置或獲取消息隊列屬性
msqid:消息隊列標識,msgget函數的返回值
cmd:
	IPC_STAT 獲取消息隊列的屬性
	IPC_SET 設置消息隊列的的屬性
	IPC_RMID 刪除消息隊列
返回值:成功返回0,失敗返回-1。

struct msqid_ds {
	struct ipc_perm msg_perm;	// 權限
	time_t          msg_stime;	// 最後一個消息發送時間
	time_t          msg_rtime;  // 最後一次消息接收時間
	time_t          msg_ctime;  // 最後一次修改時間
	unsigned long __msg_cbytes; // 消息隊列中的字節數
	msgqnum_t       msg_qnum;   // 消息隊列中消息的個數
    msglen_t        msg_qbytes; // 消息隊列中容納的最大字節數
    pid_t           msg_lspid;  // 最後一次發送消息進程
    pid_t           msg_lrpid;  // 最後一次接收消息進程

六、信號量
內核維護的計數量,用於管理多進程之間共享資源。
例如:有個變量n表示資源的數量,當有進程想要獨佔一個資源時,n的值要減1(可能減多個),如果n的值等於0(不夠減),則進程阻塞,直到n的值可以減再被喚醒,當資源使用完畢後n的要加1(可能加多個)。

int semget(key_t key, int nsems, int semflg);
功能:創建/獲取信號量
key:IPC鍵值
nsems:信號量的數量
semflg:
	0 獲取信號量
	IPC_CREAT 創建信號量(己存在則獲取,不存在則創建)。
	IPC_EXCL 如果已經存在則創建失敗。		
返回值:信號量標識

int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:操作信號量(對信號進行加/減操作)
semid:信號量標識,semget的返回值
sops:結構體數組
nsops:數組的長度
struct sembuf{
	unsigned short sem_num;	信號量的下標
    short          sem_op;	操作
    short          sem_flg;	標記
    	IPC_NOWAIT 當信號量不夠減時,不阻塞。
    	SEM_UNDO	當進程結束時,信號量的值自動歸還。

int semtimedop(int semid, struct sembuf *sops, unsigned nsops,struct timespec *timeout);
功能:帶時間限制的操作信號量
struct timespec
	__time_t tv_sec;	秒
	long int tv_nsec;	納秒 1000000000
		
int semctl(int semid, int semnum, int cmd, ...);
功能:初始化信號量,刪除信號量,獲取、設置信號量的屬性。
cmd:
	GETALL 獲取所有信號量的值
	GETNCNT 獲取信號量的數量
	GETVAL 獲取某個信號量的值
	SETALL 設置所有信號量的值
	SETVAL 設置某個信號量的值
	
	IPC_RMID  刪除信號量
	
	IPC_STAT  獲取信號量的屬性
	IPC_SET	  設置信號量的屬性
	// 獲取、設置信號量屬性    
struct ipc_perm {
	key_t          __key;
	uid_t          uid;  
	gid_t          gid;   
	uid_t          cuid;  
	gid_t          cgid;  
	unsigned short mode;  
	unsigned short __seq; 

IPC_INFO 獲取信號量的信息
SEM_INFO 設置信號量的信息
struct seminfo

編程模型:
進程A 進程B
創建信號量 semget 獲取信號量
初始化信號量的值 semctl …
加減信號量 semop 加減信號量
刪除信號量 semctl …

注意:信號量是用來計數的,一定要與資源對應。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章