Linux进程间通信——共享内存

System V共享内存

System V 标准的进程间通信方式是在OS层面专门为进程间通信设计的一个方案,通过系统调用的方式给用户提供功能。在同一个主机内的进程间通信方案叫作system V方案。
共享内存区是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说进程不再通过执行进入内核的系统调用来传递彼此的数据。

共享内存函数接口

shmget

功能:用来创建共享内存

int shmget(key_t key, size_t size, int shmflg);

参数:
key:这么共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成
返回值:成功返回一个非负整数,即该共享内存段的标识码,失败返回-1

shmat

功能:将共享内存段连接到进程地址空间

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数
shmid:共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个字节,失败返回-1
说明:
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址向下调整为SHMLBA的整数倍,公式:shmaddr - (shmaddr % SHMLBA)
shmflg = SHM_RDONLY,表示连接操作用来读共享内存

shmdt

功能:将共享内存段与当前进程脱离

int shmdt(const void *shmaddr);

参数:
shmaddr:由shmaddr:由shmat所返回的指针
返回值:成功返回0,失败返回-1

shmctl

功能:用于控制共享内存

int shmctl (int shmid, int cmd, struct shmid_ds * buf);

shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0,失败返回-1

示例

在这个实例中我们希望在客户端(client)写入数据,服务端读取数据。共享内存只需在服务端申请一次即可,但在客户端和服务端中都要与共享内存连接。

server.c

#include "comm.h"                                                                                                "
#include <unistd.h>                                                                                                 
                                                                                                 
int main()                                                                                                 
{
// 提供一个文件地址和Id,以得到一个唯一标识值
// 并非随机值,只要地址和Id相同,就会得到相同的值
// 因此在server和client中要保证文件地址和Id相同
// 以得到同一个id                                                                                              
  key_t key = ftok(PATH_NAME, PRO_ID);                                                                                                 
  if (key < 0)                                                                                                 
  {                                                                                                 
    perror("ftok");                                                                                                 
    return 1;                                                                                                 
  }                                                                                                 
  printf("%u\n", key);                                                                                                 
  int shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);                                                                             
  //                如没有则创建,有则返回已有的                                                                          
  //                如没有则创建,有则报错                                                                          
  if (shmid < 0)                                                                                         
  {                                                                          
    perror("shmget");                                                                              
    return 2;                                                                                                    
  }                                                                                                 
  printf("shmid : %u\n", shmid);                                                                                      
  //sleep(10);                                                                                                
  char *mem = (char*)shmat(shmid, NULL, 0);                                                                          
  while (1)                                                                                                                      
  {                                                                                                            
    printf("%s\n", mem);                                                                          
    sleep(1);                                                                                      
  }                                                                                                         
  shmdt(mem);                                                                                       
  // 并非释放了此共享内存,只是解除共享内存与该进程的关联     
  printf("attach success\n");                                                                                 
  shmctl(shmid, IPC_RMID, NULL); 
  return 0;                                                                                                                               
}

client.c

#include "comm.h"

int main()
{
  key_t key = ftok(PATH_NAME, PRO_ID);
  if (key < 0)
  {
    perror("ftok");
    return 1;
  }
  printf("%u\n", key);
  
  int shmid = shmget(key, SIZE, IPC_CREAT);
  if (shmid < 0)
  {
    perror("shmget");
    return 2;
  }
  char *mem = (char*)shmat(shmid, NULL, 0);
  printf("client attach success\n");
  //sleep(5);
  char ch = 'A';
  while (ch <= 'Z')
  {
    mem[ch - 'A'] = ch;
    ch++;
    mem[ch - 'A'] = 0;
    sleep(2);
  }
  shmdt(mem);
  printf("client detach success\n");
  sleep(5);
  return 0;
}

comm.h

#pragma once 

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>

#define PATH_NAME "./"
#define PRO_ID 0x666
#define SIZE 4096

总结

在本篇文章中对共享内存的操作主要是这几块
1.创建共享内存
流程:获取一个key值,用这个key值来获得id
2.关联共享内存
通过shmat函数
3.去关联共享内存
通过shmdt函数
4.释放共享内存
通过shmctl函数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JayceSun449

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值