Linux進程IPC淺析[進程間通信SystemV共享內存]
阿新 • • 發佈:2018-03-17
pil 管道 通知 虛擬 無法 erro nom 自己 ctime
Linux進程IPC淺析[進程間通信SystemV共享內存]
- 共享內存概念,概述
- 共享內存的相關函數
共享內存概念,概述:
共享內存區域是被多個進程共享的一部分物理內存
多個進程都可把該共享內存映射到自己的虛擬內存空間,全部用戶空間的進程若要操作共享內存。都要將其映射到自己的虛擬內存空間中。通過映射的虛擬內存空間地址去操作共享內存,從而達到進程間的數據通信
共享內存是進程間共享數據的一種最快的方法。一個進程向共享內存區域寫入了數據。共享這個內存區域的全部進程就能夠立馬看到當中的內容
本身不提供同步機制,可通過信號量進行同步(用信號量進行通知)
提升數據處理效率。一種效率最高的IPC機制
共享內存的屬性信息:
struct shmid_ds{ struct ipc_perm shm_perm; size_t shm_segsz; //共享內存大小 pid_t shm_lpid; //最後一次調用系統調用的進程的pid pid_t shm_cpid; //創建者pid shmatt_t shm_nattch;//當前成功映射的進程的數量 time_t shm_atime; //最後一個成功映射的時間 time_t shm_dtime; //最後一個解除映射的時間 time_t shm_ctime; //最後一次改變的時間 ....; }
共享內存的使用步驟:
使用shmget函數創建共享內存
使用shmat函數映射共享內存。將這段創建的共享內存映射到詳細的進程虛擬內存空間中
創建共享內存
#include<sys/shm.h> int shmget(key_t key,size_t size,int shmflg); 返回:假設成功。返回內核中共享內存的表示ID,假設失敗,則返回-1 參數: key:用戶制定的共享內存鍵值 size_t:共享內存的大小 shmflg:IPC_CREAT,IPC_EXCL等權限 errno: EINVAL(無效的內存段) EEXIST(內存段已經存在。無法創建) EIDRM(內存段已經被刪除) ENOENT(內存段不存在) EACCES(權限不夠) ENOMEN(沒有足夠的內存來創建內存段)
對共享內存的控制:
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
返回:成功返回0,出錯返回-1
參數:
shmid:共享內存ID
buf:共享內存屬性指針
cmd:
IPC_STAT 獲取共享內存段屬性
IPC_SET 設置共享內存段屬性
IPC_RMID 刪除共享內存段
SHM_LOCK 鎖定共享內存段頁面
SHM_UNLOCK 解除共享內存段頁面的鎖定
共享內存的映射和映射的解除:
#include<sys/shm.h>
void* shmat(int shmid,char *shmaddr,int shmflag);
返回:成功返回共享內存映射到進程虛擬內存空間中的地址。失敗返回-1,然後通過操作共享內存的地址來進行寫操作
int shmdt(char *shmaddr);
返回:假設失敗,返回-1
參數:
shmid:共享內存ID
shmaddr:映射到進程虛擬內存空間的地址,建議設置為0,由系統分配
shmflg:若shmaddr設置為0,則shmflag也設置為0
SHM_RND
SHMLBA 地址為2的乘方
SHM_RDONLY 僅僅讀方式鏈接
errno
EINVAL 無效的IPC ID值或者無效的地址
ENOMEN 沒有足夠內存
EACCESS 權限不夠
子進程不繼承父進程創建的共享內存,大家是共享的,子進程繼承父進程映射的地址
下面的代碼是通過管道的形式來對共享內存實現同步,一個進程實現對共享內存的寫後,通過管道通知另外一個進程去從共享內存中去讀取:
/*
* ===========================================================================
*
* Filename: tell.h
* Description:
* Version: 1.0
* Created: 2017年04月16日 10時40分31秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#ifndef __TELL_H_
#define __TELL_H_
//初始化管道
extern void pipe_init();
//通知管道
extern void pipe_notify();
//管道堵塞等待
extern void pipe_wait();
//銷毀管道
extern void pipe_destory();
#endif
/*
* ===========================================================================
*
* Filename: tell.c
* Description:
* Version: 1.0
* Created: 2017年04月16日 10時42分23秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include"tell.h"
#include<unistd.h>
#define BUFFER_SIZE 1024
//管道的文件描寫敘述符號
static int pipe_fd[2];
//初始化管道
extern void pipe_init(){
if(pipe(pipe_fd) < 0){
perror("create pipe error\n");
}
}
//管道等待
extern void pipe_wait(){
char buffer[BUFFER_SIZE];
if((read(pipe_fd[0],&buffer,sizeof(buffer))) != 0){
printf("read content:%s\n",buffer);
}
}
//通知管道
extern void pipe_notify(){
ssize_t size;
char content[] = "notify";
if((size = write(pipe_fd[1],content,sizeof(content))) !=sizeof(content)){
perror("write error");
}
}
//銷毀管道
extern void pipe_destory(){
close(pipe_fd[0]);
close(pipe_fd[1]);
}
/*
* ===========================================================================
*
* Filename: shmtest.c
* Description:
* Version: 1.0
* Created: 2017年04月16日 10時51分54秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include"tell.h"
#include<sys/shm.h>
#define SHM_BUFFER_SIZE 1024
int main(int argc,char*argv[]){
pid_t pid;
int shmid;
//創建共享內存
shmid = shmget(IPC_PRIVATE,SHM_BUFFER_SIZE,IPC_CREAT | IPC_EXCL | 0777);
if(shmid < 0){
perror("create share memory error");
}
//初始化管道
pipe_init();
if((pid = fork()) < 0){
}else if(pid > 0){
//父進程運行的時間片
//父進程進行共享內存的映射
int* shm_int_pointer = shmat(shmid,0,0);
if(shm_int_pointer == (int *)-1){
perror("error");
}
//父進程往共享內存中寫數據
*shm_int_pointer = 10;
*(shm_int_pointer + 1)= 100;
*(shm_int_pointer + 2) = 1000;
//取消共享內存的映射
shmdt(shm_int_pointer);
//通知子進程
pipe_notify();
//管道進行銷毀
pipe_destory();
wait(0);
}else{
//子進程運行的時間片
//子進程堵塞
pipe_wait();
int *shm_int_pointer = shmat(shmid,0,0);
if(shm_int_pointer == (int *)-1){
perror("error");
exit(1);
}
int num1 = *shm_int_pointer;
int num2 = *(shm_int_pointer+1);
int num3 = *(shm_int_pointer+2);
printf("num1:%d,num2:%d,num3:%d\n",num1,num2,num3);
shmdt(shm_int_pointer);
//刪除共享內存
int shm_ctl_result = shmctl(shmid,IPC_RMID,NULL);
if(shm_ctl_result == -1){
perror("delete shmctl error");
}
pipe_destory();
}
return 0;
}
以上部分就是關於共享內存部分的相關簡單的調用,代碼調試過
歡迎持續訪問博客
Linux進程IPC淺析[進程間通信SystemV共享內存]