Linux--进程间的通信之共享内存

概念

共享内存是进程间通信中最简单的方式之一。共享内存允许两个或多个进程访问同一块内存。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

优缺点

因为是所有进程共享的同一块内存,共享内存在各种进程间通信方式中具有最高的效率。但是共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问。

操作函数

创建共享内存


#include<sys/ipc.h>
#include<sys/shm.h>
int shmget(key_t key,size_t size,int shmflag);

返回值:成功返回共享存储区的shmid,失败返回-1。man
参数:
key:系统对此共享内存存储资源的唯一标识。可以通过ftok函数得到。
size:以字节为单位指定需要共享的内存容量。这个数一般为系统页长的整数倍(4K的整数倍).若申请的size不是页长的整数倍,系统也是按整数倍进行分配的,但是最后一页余下的部分不可用。如果创建一个新的资源,则必须指定size,且段的内容会被初始化为0。若引用一个已经存在的,则将size置为0。
shmflag:与消息队列的参数相同。有两个选项,IPC_CREAT和IPC_EXCL。使用的时候有两种情况:
1. IPC_CREAT和IPC_EXCL一起使用(IPC_CREAT|IPC_EXCL),表示申请创建一个新的IPC资源,若要申请的资源已经存在,则错误返回。若不存在,则创建。
2. IPC_CREAT单独使用,表示申请创建一个IPC资源,若要申请的IPC资源已经存在,则直接使用;若不存在,则创建新的。
一般我们还会在后面加上资源的默认权限(如0666)。

删除共享内存


#include<sys/ipc.h>
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);

返回值:成功返回0,失败返回-1。
参数:
shmid:shmget的返回值。
cmd:是要采取的操作,它可以取下面的三个值:
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
这里我们cmd取IPC_RMID。

buf:是一个结构体的指针,它指向共享内存模式和访问权限的结构。shmid_ds的结构如下:

struct shmid_ds
{
    struct ipc_perm shm_perm;
    size_t shm_segsz;
    pid_t shm_lpid;
    pid_t shm_cpid;
    shmatt_t shm_nattch;//shmatt_t定义为无符号整型,他至少和unsigned short一样大。
    time_t shm_atime;
    time_t shm_dtime;
    time_t shm_ctime;
    ...
}

把进程连接到共享内存


#include<sys/types.h>
#include<sys/shm.h>
void* shmat(int shmid,const void* shmaddr,int shmflag)

返回值:成功返回指向共享内存存储的指针,失败返回-1。
参数:
shmid:shmget函数的返回值。
shmaddr:shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
shmflag:shm_flg是一组标志位,通常为0。

把进程从共享内存中分离


#include<sys/types.h>
#include<sys/shm.h>
int shmdt(const void* shmaddr)

返回值:成功返回0,失败返回-1。
参数:
shmadd:是shmat函数返回的地址指针。

控制指令

系统同样为我们提供了查看共享内存IPC资源的指令:

ipcs -m

这里写图片描述
删除共享内存资源:

ipcrm -m [shmid]

代码实现

客户机-服务器模式
comm.h

ifndef __COMM__
#define __COMM_

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

#define PATHNAME "."
#define PROJID 0x666
#define SIZE 4096

int commMem(int flags);
int creatMem();
int getMem();
int destroyMem(int shmid);

#endif

comm.c:

#include"comm.h"

int commMem(int flags)
{
    key_t _k=ftok(PATHNAME,PROJID);
    if(_k<0)
    {
        perror("ftok");
        return -1;
    }

    int shmid = shmget(_k,SIZE,flags);
    if(shmid<0)
    {
        perror("shmget");
        return -2;
    }
    return shmid;
}

int creatMem()
{
    return commMem(IPC_CREAT | IPC_EXCL | 0666);
}

int getMem()
{
    return commMem(IPC_CREAT);
}

int destroyMem(int shmid)
{
    int ret = shmctl(shmid,IPC_RMID,NULL);
    if(ret<0)
    {
        perror("destroy shmctl");
        return -1;
    }
    return 0;
}

client.c


#include"comm.h"

int main()
{
    printf("client\n");
    int shmid = getMem();
    if(shmid < 0)
    {
        printf("getMem error!");
        return -1;
    }
    printf("shmid: %d\n",shmid);
    sleep(5);
    char *addr=shmat(shmid,NULL,0);
    if(addr == NULL)
    {
        printf("addr is NULL!\n");
    }
    printf("Debug add %p\n",addr);

    if(addr < 0)
    {
        perror("client shmat");
        return -1;
    }

    int i = 0;
    while(i < SIZE-1)
    {
        addr[i] ='a' ;
        addr[i+1] = '\0';
        sleep(1);
        i++;
    }

    int ret=shmdt(addr);
    printf("Debug shmdt\n");
    if(ret < 0)
    {
        perror("client shmdt");
        return -1;
    }
    return 0;
}

server.c:

#include "comm.h"

int main()
{
    printf("server\n");
    int shmid = creatMem();
    sleep(10);
    if(shmid < 0)
    {
        printf("creatMem error!\n");
        return -1;
    }

    char *addr=shmat(shmid,NULL,0);
    if(addr < 0)
    {
        perror("shmat");
        return -2;
    }
    while(1)
    {
        printf("# ");
        printf("%s",addr);
        printf(" #\n");
        sleep(1);
    }

    int ret = shmdt(addr);
    if(ret < 0)
    {
        perror("shmdt");
        return -1;
    }

    int ret_des=destroyMem(shmid);
    if(ret_des < 0)
    {
        printf("destroyMem error!\n");
        return -1;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux下,进程通信的一种方式是通过共享内存来实现的。共享内存允许两个或多个进程共享一定的存储区,这样它们就可以直接访问同一块内存区域,而不需要进行数据的复制。共享内存是一种高效的进程通信方式,因为数据直接写入内存,不需要多次数据拷贝,所以传输速度很快\[2\]。 在使用共享内存进行进程通信时,需要给共享内存创建一个唯一的身份ID,以便区分不同的共享内存。当进程需要访问共享内存时,需要在映射时带上这个ID,这样就可以确定访问的是哪一个共享内存\[3\]。 需要注意的是,共享内存并没有提供同步机制,也就是说,在一个进程结束对共享内存的写操作之前,并没有自动机制可以阻止另一个进程开始对它进行读取。为了实现多个进程共享内存的同步访问,通常会使用信号量来实现对共享内存的同步访问控制\[2\]。 总结起来,Linux下的共享内存是一种高效的进程通信方式,允许多个进程共享一块存储区。通过给共享内存创建唯一的身份ID,可以区分不同的共享内存。然而,共享内存并没有提供同步机制,需要使用信号量来实现对共享内存的同步访问控制\[2\]\[3\]。 #### 引用[.reference_title] - *1* *3* [Linux进程通信——共享内存实现](https://blog.csdn.net/zhm1949/article/details/124909541)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Linux进程通信方式——共享内存](https://blog.csdn.net/xujianjun229/article/details/118584955)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值