进程间通信------共享内存

共享内存作为进程间通信高效方式,避免了数据在内核与用户空间间的拷贝。但需注意同步互斥问题,其生命周期与内核同步。文章介绍了shmget、shmat、shmdt和shmctl等函数的使用,并提供了代码示例展示如何创建、映射、控制及删除共享内存,以实现进程间通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     以下用到的消息队列中的相关内容,均可在这里找到:https://blog.youkuaiyun.com/sandmm112/article/details/79936107

        共享内存是进程间通信的一种方式。系统中物理内存结构及进程与共享区的映射关系如下:


        创建一个共享内存是指在共享取开辟一片区域,将该区域分别映射到两个进程的虚拟地址空间中,那这两个进程便可以通过这片共享区域进行通信了。因为共享内存位于用户空间中,所以每次进行通信时,不会像消息队列一样先将一个进程中用户空间中的数据拷贝到内核,再将内核中的数据拷贝到另一进程的用户空间中。这样便可不在涉及到内核,所以说共享内存是最快的进程间通信方式。

        但是共享内存并没有提供同步与互斥机制,所以当多个进程同时访问共享内存时可能会数据的二义性。

        注意:共享内存的的生命周期也是随内核的。

        以下来介绍一些有关共享内存的函数,来进一步理解共享内存:

1. 共享内存与消息队列一样,首先需要一个key值来创建共享内存。key值的获取方法与消息的队列中的方法相同

2. 创建共享内存

int shmget(key_t key,size_t size,int shflg);//头文件:<sys/ipc.h>,<sys/shm.h>

参数:

        key:ftok函数返回的key值

        size:创建的共享内存的大小

        shmflg:用法与消息队列中相同

返回值:成功返回一个非负整数即共享内存的标识符,失败返回-1。

        共享内存创建成功后,操作系统会给该共享内存维护一个结构体struct shmid_ds,保存它的基本信息,结构体中的内容类似消息队列的结构体struct msqid_ds

3. 将共享内存映射到进程的地址空间

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

参数:

        shmid:共享内存标识符

        shmaddr:指定要连接的地址,为NULL时,自动选择一个地址

        shmflg:设置共享内存特性,一般为0

返回值:成功返回一个指向共享内存的指针,失败返回-1

4. 断开共享内存与进程的映射关系

int shmdt(const char* shmaddr);

参数:由shmat返回的指针

返回值:成功返回0,失败返回-1

注意:将共享内存与进程脱离并不是删除共享内存

5. 控制共享内存

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

参数:

        shmid:共享内存的标识符

        cmd:对共享内存所要采取的操作,取值与消息队列msgctl函数中的参数cmd相同。

        buf:指向共享内存结构体的指针

返回值:成功返回0,失败返回-1

        以下通过代码来演示如何利用共享内存来进行进程间通信:

先封装有关共享内存操作的方法:

头文件comm.h:

#pragma once

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

#define PATHNAME "."
#define PROJ_ID 0x6666

//异常退出宏函数
#define ERR_EXIT(m) \
    do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }while(0)

//创建共享内存
int CreateShm(size_t size);
//获取共享内存
int GetShm(size_t size);
//挂接共享内存
int CatShm(int shmid,void* addr);
//断开共享内存
int DtShm(const void* addr);
//销毁共享内存
int DestoryShm(int shmid);       

封装方法comm.c

#include "comm.h"                                                                                                                     
//创建/获取共享内存
static int CommShm(int size,int flags)
{
    //创建进程间通信标识符
    key_t key = ftok(PATHNAME,PROJ_ID);
    if(key < 0)//创建失败
    {
        ERR_EXIT("ftok error");
    }
    int shmid = shmget(key,size,flags);//创建或获取共享内存
    if(shmid < 0)//共享内存创建失败
    {
        ERR_EXIT("shmid error");
    }
    return shmid;//返回共享内存标识符
}

//创建共享内存
int CreateShm(size_t size)
{
    return CommShm(size,IPC_CREAT|IPC_EXCL|0666);
}

//获取共享内存
int GetShm(size_t size)
{
    return CommShm(size,IPC_CREAT);
}

//断开共享内存
int DtShm(const void* addr)
{
    int ret = shmdt(addr);
    if(ret < 0)//断开失败
    {
        printf("shmid error\n");
        return -1;
    }
    return 0;
}

//销毁共享内存
int DestoryShm(int shmid)                                                                                                             
{
    int ret = shmctl(shmid,IPC_RMID,NULL);
    if(ret < 0)
    {
        printf("shmctl error\n");
        return -1;
    }
    return 0;
}              

在一个进程中创建共享内存并将其映射到该进程中接收消息:server.c

#include "comm.h"
int main()
{
    //创建共享内存
    int shmid = CreateShm(4097);

    //挂解共享内存
    char* addr = shmat(shmid,NULL,0);
    sleep(2);

    int i = 0;
    printf("client say#\n ");
    sleep(2);
    while(i < 26)
    {
        printf("%s\r",addr);
        i++;
        fflush(stdout);
        sleep(1);
    }
    printf("\n");

    //断开共享内存
    shmdt(addr);

    sleep(2);
    //删除共享内存
    DestoryShm(shmid);
    return 0;
}                               

在另一进程中获取共享内存并映射到该进程用于发送信息:client.c

#include "comm.h"

int main()
{
    int shmid = GetShm(4096);//获取共享内存
    //挂接共享内存
    char* addr = shmat(shmid,NULL,0);
    int i = 0;
    while(i < 26)                                                                                                                     
    {
        addr[i] = 'A'+ i;
        i++;
        addr[i] = 0;
        sleep(1);
    }
    shmdt(addr);
    sleep(1);
    return 0;
}
        分别在两个终端下运行两个进程,得到如下结果:
[admin@localhost ShareMemory]$ ./server 
client say#
ABCDEFGHIJKLMNOPQRSTUVWXYZ  //各个字符会一次输出一个
[admin@localhost ShareMemory]$ 
[admin@localhost ShareMemory]$ ./client 
[admin@localhost ShareMemory]$ 

        同样的,可以通过如下命令来查看和删除共享内存:

ipcs -m //查看共享内存
ipcrm -m  共享内存标识符  //删除指定标识符的共享内存







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值