1. 程式人生 > >Linux進程IPC淺析[進程間通信SystemV共享內存]

Linux進程IPC淺析[進程間通信SystemV共享內存]

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共享內存]