Linux —— 进程间通信(System V)

目录

一,共享内存

申请共享内存 shmget

控制共享内存 shmctl

关联共享内存 shmat / 去联共享内存 shmdt

二,消息队列

创建或打开消息队列 msgget

发送消息 msgsnd / 接收消息 msgrcv

控制消息 msgctl

三,信号量

创建或打开信号量 semget

信号量操作 semop

信号量控制 semctl


一,共享内存

        共享内存是最快的进程间通信IPC形式,即允许两个或多个进程共享物理内存的同一块区域(通常被称为段),进程间数据传递将不再涉及到内核(即将不再通过内核系统调用来传递数据);

Linux —— 进程间通信(System V)_第1张图片

维护共享内存的数据结构

//vim /usr/include/bits/shm.h
struct shmid_ds {
    struct ipc_perm shm_perm; /* operation perms */
    int shm_segsz; /* size of segment (bytes) */
    __kernel_time_t shm_atime; /* last attach time */
    __kernel_time_t shm_dtime; /* last detach time */
    __kernel_time_t shm_ctime; /* last change time */
    __kernel_ipc_pid_t shm_cpid; /* pid of creator */
    __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
    unsigned short shm_nattch; /* no. of current attaches */
    unsigned short shm_unused; /* compatibility */
    void *shm_unused2; /* ditto - used by DIPC */
    void *shm_unused3; /* unused */
};
//vim /usr/include/bits/ipc.h
 /* Data structure used to pass permission information to IPC operations.  */    
  struct ipc_perm    
    {    
      __key_t __key;      /* Key.  */    
      __uid_t uid;      /* Owner's user ID.  */    
      __gid_t gid;      /* Owner's group ID.  */    
      __uid_t cuid;     /* Creator's user ID.  */    
      __gid_t cgid;     /* Creator's group ID.  */    
      unsigned short int mode;    /* Read/write permission.  */    
      unsigned short int __pad1;    
      unsigned short int __seq;   /* Sequence number.  */    
      unsigned short int __pad2;    
      __syscall_ulong_t __unused1;    
      __syscall_ulong_t __unused2;    
    }; 

申请共享内存 shmget

  • key,用于唯一区分共享内存,可由ftok函数生成;
  • size,建议为4KB的倍数;
  • shmflg,标签;
    • IPC_CREAT,如目标共享内存不存在,即创建,否则获取;
    • IPC_CREAT | IPC_EXCL,如目标共享内存不存在,即创建,否则出错;

Linux —— 进程间通信(System V)_第2张图片

//vim /usr/include/bits/ipc.h
  #include     
      
  /* Mode bits for `msgget', `semget', and `shmget'.  */    
  #define IPC_CREAT 01000   /* Create key if key does not exist. */    
  #define IPC_EXCL  02000   /* Fail if key exists.  */    
  #define IPC_NOWAIT  04000   /* Return error on wait.  */    
      
  /* Control commands for `msgctl', `semctl', and `shmctl'.  */    
  #define IPC_RMID  0   /* Remove identifier.  */    
  #define IPC_SET   1   /* Set `ipc_perm' options.  */    
  #define IPC_STAT  2   /* Get `ipc_perm' options.  */    
  #ifdef __USE_GNU    
  # define IPC_INFO 3   /* See ipcs.  */    
  #endif 

控制共享内存 shmctl

Linux —— 进程间通信(System V)_第3张图片

关联共享内存 shmat / 去联共享内存 shmdt

Linux —— 进程间通信(System V)_第4张图片

//makefile
CC=gcc    
.PHONY:all    
all: server client    
    
server:server.c    
  $(CC) -o $@ $^        
client:client.c    
  $(CC) -o $@ $^        
        
.PHONY:clean        
clean:    
  rm -rf server client  
//comm.h
#pragma once    
#include     
    
#define PATH_NAME "/home/wz/Desktop/pipe"    
#define PROJ_ID 0x6666

#define SIZE 4097
//server.c
include "comm.h"    
#include     
#include     
#include     
#include     
#include     
#include     
    
int main()    
{    
  key_t k = ftok(PATH_NAME, PROJ_ID);    
  if(k < 0){    
    perror("ftok");    
    return 1;    
  }    
  printf("key: %x\n", k);    
  sleep(3);    
    
  int shmid = shmget(k, SIZE, IPC_CREAT|IPC_EXCL|0644);    
  if(shmid < 0){    
    perror("shmget");    
    return 2;    
  }    
  printf("shmid: %d\n", shmid);    
  sleep(3);    
    
  char* start = (char*)shmat(shmid, NULL, 0);    
  printf("server already attach on shared memory!\n");    
  while(1){    
    printf("%s\n", start);    
    sleep(1);                                                                                                  
    if(strlen(start) == 26)    
      break;    
  }    
    
  shmdt(start);    
  printf("server already dattach off shared memory!\n");    
  sleep(3);    
    
  shmctl(shmid, IPC_RMID, NULL);    
  printf("delete %d\n", shmid);    
  return 0;    
}  
//client.c
#include "comm.h"    
#include     
#include     
#include     
#include     
#include     
#include     
    
int main()    
{    
  key_t k = ftok(PATH_NAME, PROJ_ID);    
  if(k < 0){    
    perror("ftok");    
    return 1;    
  }    
  printf("key: %x\n", k);    
  sleep(3);    
    
  int shmid = shmget(k, SIZE, IPC_CREAT);    
  if(shmid < 0){    
    perror("shmget");    
    return 2;    
  }    
  printf("client shmid: %d\n", shmid);    
  sleep(3);    
    
  char* start = (char*)shmat(shmid, NULL, 0);    
  printf("client already attach on shared memory!\n");    
    
  char c = 'A';    
  while(c <= 'Z'){    
    start[c - 'A'] = c;    
    c++;    
    sleep(1);                                                                                                  
  }    
    
  shmdt(start);    
  printf("client already dattach off shared memory!\n");    
  sleep(3);    
  return 0;    
}    
//查看共享内存
[wz@192 pipe]$ ipcs -m
//删除指定id共享内存
[wz@192 pipe]$ ipcrm -m 426047

共享内存的生命周期随OS;

共享内存不提供任何同步与互斥,彼此独立;

共享内存是所有进程间通信中,速度最快的;

共享内存系统分配的shm,是按照4KB为基本单位的,如指定不是4KB的倍数,多余会浪费掉;

二,消息队列

        消息队列是进程间通信的一种方式,提供一个从一个进程向另一个进程发生一块数据的方法;

维护消息队列的数据结构

//vim /usr/include/bits/msq.h 
/* Structure of record for one message inside the kernel.    
     The type `struct msg' is opaque.  */    
  struct msqid_ds    
  {    
E>  struct ipc_perm msg_perm; /* structure describing operation permission */    
    __time_t msg_stime;   /* time of last msgsnd command */    
  #ifndef __x86_64__    
    unsigned long int __unused1;    
  #endif    
    __time_t msg_rtime;   /* time of last msgrcv command */    
  #ifndef __x86_64__    
    unsigned long int __unused2;    
  #endif    
    __time_t msg_ctime;   /* time of last change */                                                            
  #ifndef __x86_64__    
    unsigned long int __unused3;    
  #endif    
    __syscall_ulong_t __msg_cbytes; /* current number of bytes on queue */    
    msgqnum_t msg_qnum;   /* number of messages currently on queue */    
    msglen_t msg_qbytes;    /* max number of bytes allowed on queue */    
    __pid_t msg_lspid;    /* pid of last msgsnd() */    
    __pid_t msg_lrpid;    /* pid of last msgrcv() */    
    __syscall_ulong_t __unused4;    
    __syscall_ulong_t __unused5;    
  }; 

创建或打开消息队列 msgget

  • key,用于唯一区分共享内存,可由ftok函数生成;
  • msgflg,标签;
    • IPC_CREAT,如目标消息队列不存在,即创建,否则获取;
    • IPC_CREAT | IPC_EXCL,如目标消息队列不存在,即创建,否则出错;

Linux —— 进程间通信(System V)_第5张图片

发送消息 msgsnd / 接收消息 msgrcv

Linux —— 进程间通信(System V)_第6张图片

控制消息 msgctl

Linux —— 进程间通信(System V)_第7张图片

三,信号量

        信号量并不是原来进程间传输数据的,是原来同步进程当作的,主要用于同步与互斥;由于进程要求共享资源,而有些资源需互斥使用;系统中的某些资源一次只允许一个进程使用,称这些资源为临界资源或互斥资源;涉及到互斥资源的程序段,称为临界区;

维护信号量的数据结构

//vim /usr/include/bits/sem.h 
  /* Data structure describing a set of semaphores.  */    
  struct semid_ds    
  {    
    struct ipc_perm sem_perm;   /* operation permission struct */    
    __time_t sem_otime;     /* last semop() time */    
    __syscall_ulong_t __unused1;    
    __time_t sem_ctime;     /* last time changed by semctl() */    
    __syscall_ulong_t __unused2;    
    __syscall_ulong_t sem_nsems;    /* number of semaphores in set */    
    __syscall_ulong_t __unused3;    
    __syscall_ulong_t __unused4;    
  };    

创建或打开信号量 semget

Linux —— 进程间通信(System V)_第8张图片

信号量操作 semop

Linux —— 进程间通信(System V)_第9张图片

信号量控制 semctl

Linux —— 进程间通信(System V)_第10张图片

 

你可能感兴趣的:(操作系统,linux)