SystemV 共享内存

SystemV 共享内存

  • 进程间通信(interprocess communication——IPC)允许两个独立的进程进行数据交换,即相互发送数据和接收数据。进程间通信有两种基本模型:共享内存和消息传递。在共享内存模型中,建立了一个由协作进程共享的内存区域,然后,进程可以通过向共享区域读写数据来交换信息。在消息传递模型中,通信通过协作进程之间交换的消息进行。共享内存可能比消息传递更快,因为消息传递通常需要系统调用来实现,因此需要更耗时的内核干预任务。消息传递对于交换少量数据很有用,因为不需要避免冲突。在共享内存系统中,仅在建立共享内存区域时才需要系统调用。一旦建立了共享内存,所有访问都被视为例行内存访问,不需要内核的帮助。

在这里插入图片描述

  • 通过系统调用,将多个进程地址空间的部分区域映射到同一份物理内存,从而形成共享内存。共享内存具有最大的通信速度和便利性,因为它可以在计算机中以内存传输速度完成通信。然而,共享内存在多进程访问的同步和互斥方面存在问题,需程序员自行保证数据安全。

  • 进程运行结束,系统创建的IPC资源并不会释放,它的生命周期由内核决定。可以通过以下命令查看并手动释放:

    [test@VM-12-4-centos SystemVIPC]$ ipcs -m
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status       # perms文件权限
    0x66010da7 0          test       664        4096       0                       
    
    [test@VM-12-4-centos SystemVIPC]$ ipcrm -m 0
    [test@VM-12-4-centos SystemVIPC]$ ipcs -m
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status 
    
  • SystemV 共享内存的系统调用:

  • 分配共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

key:必须是IPC独立私有的值。可以通过ftok()生成

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

失败返回-1;成功返回System V IPC key。当pathname和proj_id相同时,生成的key是相同的。

size:系统给共享内存分配的大小实际是PAGE_SIZE(4Kb)的整数倍。

shmflg: IPC_CREAT :存在则获取,不存在则创建一块新的内存区域; IPC_EXCL:与创建选项一起使用,若已经存在则创建失败,保证创建的共享内存是第一次创建的。

返回值:成功创建返回共享内存的ID;失败则返回-1。

  • 删除共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

cmd:IPC_RMID:删除共享内存

buf:shmid的data struct,用来描述共享内存的属性

  • 将共享内存与进程的虚拟地址空间进行挂接
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:shmget()的返回值,为共享内存的ID(类似于数组下标)

shmaddr:虚拟地址空间的地址,设置为NULL会由操作系统进行分配。

shmflg:设0由操作系统管理。

返回值:成功返回共享内存的段地址——虚拟地址。

  • 将共享内存与进程解挂接
int shmdt(const void *shmaddr);

shmaddr:shmat()的返回值。

下面是一段例程说明SystemV共享内存的使用:

  • SharedPath.h
#pragma once

#define PipeFilePath "PipeFile"
#define IPC_ID 0x1666
  • server.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "SharedPath.h"
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{

    key_t KeyVal = ftok(PipeFilePath, IPC_ID);
    if(KeyVal == -1)
    {
        perror("ftok failed\n");
        exit(-1);
    }

    //int id = shmget(KeyVal, 4096, IPC_CREAT | IPC_EXCL | 0664); 
    int id = shmget(KeyVal, 4096, IPC_CREAT | 0664); //在物理内存中开辟了一段共享空间
    if(id < 0)
    {
        perror("shmget failed\n");
        exit(-2);
    }

    char* Virtualaddr = (char*)shmat(id, NULL, 0);
    
    // ************共享内存使用****************
    while(1)
    {
        printf("%s\n", Virtualaddr); //读取
        fflush(stdout);
        sleep(1);
        if(Virtualaddr == NULL)
        {
            break;
        }
    }
	//***************************************
    shmdt(Virtualaddr);
    shmctl(id, IPC_RMID, NULL); //释放共享内存空间
    return 0;
}
  • client.c
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include "SharedPath.h"
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{

    key_t KeyVal = ftok(PipeFilePath, IPC_ID);
    if(KeyVal == -1)
    {
        perror("ftok failed\n");
        exit(-1);
    }

    int id = shmget(KeyVal, 4096, IPC_CREAT); //获取已存在的IPC ID。
    if(id < 0)
    {
        perror("shmget failed\n");
        exit(-2);
    }
    char* Virtualaddr = (char*)shmat(id, NULL, 0);
    
    // ************共享内存使用****************
    int i = 0;
    while(1)
    {
        for(i = 0; i < 10; i++)
        {
            Virtualaddr[i] = 'a'; 
            sleep(5);
        }
        Virtualaddr[i] = '\n'; 
        Virtualaddr[i + 1] = '\0'; 
    }
	//***************************************
    shmdt(Virtualaddr);
    return 0;
}
  • Makefile
.PHONY:all
all:client server
client:client.c
	gcc -o $@ $^

server:server.c
	gcc -o $@ $^

.PHONY:clean
clean:
	rm -f client server
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值