Linux--System V共享内存


共享内存区是最快的IPC方式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据
管道通信的本质是基于文件的!OS没有做过多的设计
system v 进程间通信:OS特地设计的通信方式(让不同的进程看到同一份文件)
在这里插入图片描述

system V共享内存

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

共享内存数据结构

 struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
           };

 struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and
                                           SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };

共享内存函数

shmget函数

功能:创建共享内存
原型:int shmget(key_t key, size_t size, int shmflg);
参数:

  • key:共享内存段名字;在内核层面,多个进程之间上区分共享内存的唯一方式
  • size:共享内存大小
  • shmflg:由九个标志权限组成,开辟成功返回一个非负整数,即该共享内存段的标识码;失败返回-1;

在这里插入图片描述
补充:

  • SIZE:PAGE_SIZE:4096字节-》一页数据
    在这里插入图片描述

共享内存大小是按页对齐的

命令查共享内存

ipcs

在这里插入图片描述

ipcs -m

在这里插入图片描述

//comm.h
#ifndef _COMM_H//防止头文件被重复包含
#define _COMM_H

#define PATHNAME  "/home/L/10-25/server.c"
#define PROJ_ID 0x6666
#define SIZE 1024
#include <stdio.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>


#endif

//server.c
#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shm = shmget(k,SIZE,IPC_CREAT|IPC_EXCL);
  if(shm < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  sleep(10);
  return 0;
}

在这里插入图片描述

在这里插入图片描述
删除共享内存

ipcrm -m shmid号

在这里插入图片描述

shmctl函数

功能:用于控制进程内存
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:

  • shmid:由shmget返回的共享内存标识码
  • cmd:将要采取的动作(三个可取值)
  • buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
  • IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值
  • IPC_SET:在进程有足够权限的前提下,把共享内存的当前关联值设为shmid_ds数据结构中给出的值
  • IPC_RMID:删除共享内存
#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shm = shmget(k,SIZE,IPC_CREAT|IPC_EXCL);
  if(shm < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  sleep(10);
  shmctl(shm,IPC_RMID,NULL);
  sleep(10);
  return 0;
}

在这里插入图片描述

shmat函数

功能:将共享内存段连接到进程地址空间
原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:

  • shmid:共享内存标识;在进程内部,区分某一个IPC资源
  • shmaddr:指定连接的地址
  • shmflg:SHM_RND /SHM_RDONLY;返回值:成功返回指针(对应共享内存映射到地址空间中的虚拟地址的起始地址),失败返回-1
    补充:
  • shmaddr 为NULL会自动选择一个地址
  • shmaddr不为NULL且shmflg无SHM_RND标记,则以shmadd为连接地址
  • shmaddr不为NULL且shmflg设置SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - shmflg % SHMLBA
  • shmflg = SHM_RDONLY,表示连接操作只用来读共享内存
    1\
#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shmid = shmget(k,SIZE,IPC_CREAT|IPC_EXCL);
  if(shmid < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  printf("shmid:%d\n",shmid);
  printf("attach begin!\n");
  sleep(3);
  char *mem = shmat(shmid,NULL,0);
  printf("attach end!,%d\n",(int)mem);
  sleep(3);
  return 0;
}

在这里插入图片描述
2\

#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shmid = shmget(k,SIZE,IPC_CREAT|IPC_EXCL | 0666);
  if(shmid < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  printf("shmid:%d\n",shmid);
  sleep(3);
  char *mem = shmat(shmid,NULL,0);
  printf("attach end!,%d\n",(int)mem);
  sleep(3);
  return 0;
}

在这里插入图片描述

shmdt函数

功能:将共享内存与当前进程脱离
原型: int shmdt(const void *shmaddr);
参数:

  • shmaddr:由shmat返回的指针
  • 注意:将共享内存与当前进程脱离不相当于删除共享内存段

实例

#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shmid = shmget(k,SIZE,IPC_CREAT|IPC_EXCL | 0666);
  if(shmid < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  printf("shmid:%d\n",shmid);
  printf("attach begin!\n");
  sleep(3);
  char *mem = shmat(shmid,NULL,0);//关联
  printf("attach end!,%d\n",(int)mem);
  sleep(3);
  
  printf("dettach begin!\n");
  sleep(2);
  //
  shmdt(mem);//去关联
  printf("dettach end!\n");
  sleep(2);
  shmctl(shmid,IPC_RMID,NULL);
  return 0;
}

在这里插入图片描述
在这里插入图片描述

//server.c
#include "comm.h"
#include <unistd.h>


int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!\n");
    return 1;
  }
  int shmid = shmget(k,SIZE,IPC_CREAT|IPC_EXCL | 0666);
  if(shmid < 0)
  {
    perror("shmget error!\n");
    return 2;
  }
  char *mem = shmat(shmid,NULL,0);//关联
  //todo
  while(1)
  {
    printf("client msg# %s\n",mem);
    sleep(1);
  }
  shmdt(mem);
  return 0;
}

//client.c
#include "comm.h"
int main()
{
  key_t k = ftok(PATHNAME,PROJ_ID);
  if(k < 0)
  {
    perror("ftok error!\n");
    return 1;
  }
  printf("%x\n",k);
  int shmid = shmget(k,SIZE,IPC_CREAT);
  if(shmid < 0)
  {
    perror("shmid error!\n");
    return 2;
  }
  char* mem = shmat(shmid,NULL,0);
  //todo
  int i = 0;
  while(1)
  {
    mem[i] = 'A' + i;
    i++;
    sleep(1);
    mem[i] = '\0';
  }
  shmdt(mem);
  return 0;
}

在这里插入图片描述
读共享内存的时候,没有使用OS接口
共享内存是所有的进程间通信中速度最快的

  • 1、拷贝次数少
  • 2、不提供任何保护机制(同步与互斥)

system V 消息队列

在这里插入图片描述

  • 消息队列提供了一个从一个进程向另一个进程发送一块数据的方法
  • 每个数据块都被认为是有一个类型,接收者进程接受的数据块可以有不同的类型值
  • 特性方面:IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPV资源生命周期随内核

msgget

获取消息队列
在这里插入图片描述

msgctl

删除消息队列
在这里插入图片描述

struct msqid_ds {
               struct ipc_perm msg_perm;     /* Ownership and permissions */
               time_t          msg_stime;    /* Time of last msgsnd(2) */
               time_t          msg_rtime;    /* Time of last msgrcv(2) */
               time_t          msg_ctime;    /* Time of last change */
               unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
               msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
               msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
               pid_t           msg_lspid;    /* PID of last msgsnd(2) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };

msgsnd

发送消息队列
在这里插入图片描述

system V 信号量

进程互斥

  • 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关心称为互斥
  • 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源
  • 在进程中涉及到互斥资源的程序段叫临界区
  • 特性方面:IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPV资源生命周期随内核

semget

获取信号量
在这里插入图片描述

  • nsems:几个信号量

semctl

释放信号量
在这里插入图片描述

semop

对信号量操作
在这里插入图片描述

信号量

在这里插入图片描述

ZmFsbGJhY2s,shadow_50,text_Q1NETiBAcW5iaw==,size_20,color_FFFFFF,t_70,g_se,x_16)

在这里插入图片描述

在这里插入图片描述

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值