System V共享内存的基本使用与实现


前言

工作中需要使用共享内存,学习一下。
环境:centos7、C


一、系统V共享内存

1.共享内存实现进程间通信

简单来说,共享内存的实现就是一个物理内存被映射到多个进程的地址空间。映射该共享内存的进程可以对共享内存进行直接内存存取对数据进行修改访问,从而实现不同进程之间的数据通信。好处是实现简单,效率高,不需要数据拷贝。

二、共享内存的C语言实现

1.shmget

创建或获取一块共享内存,返回共享内存的标识shmid。

int shmget(key_t key, size_t size, int shmflg)
根据key值获取或创建一个共享内存。
size指定了共享内存区块大小。
shmflg:创建时用 IPC_CREAT|xxxx;第一位表示进制数,第二位表示当前用户的权限,第三位表示用户组权限,第四位表示其他用户权限。
权限说明:7可读可写可执行,对应rwx,6可读可写,对应rw-,4表示可读,对应r–。
常用的有0666,0644
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1.

2.shmmat

将共享内存映射到进程的地址空间,此时共享内存的attach数加一。

void *shmat(int shmid, const void *shmaddr, int shmflg)
shmid:共享内存标识
shmaddr:指定连接地址,NULL则让内核自动选择合适的地址。
shmflg:SHM_RND(取整对齐)或SHM_RDONLY(只读),其他为(可读可写)
返回值: 成功返回一个指针,指向共享内存第一个字节;失败返回-1.
进程通过返回的指针向共享内存写入或读取数据。

3.shmdt

将共享内存与当前进程脱离,此时共享内存的attach数减一。

int shmdt(const void *shmaddr)
返回值: 成功返回0,失败返回-1.

4.shmctl

用于控制共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf)
shmid: 由shmget返回的共享内存标识码
cmd:将要采取的动作(由三个可取的值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值: 成功返回0,失败返回-1.
目前我主要使用shmctl(shmid,IPC_RMID,NULL)来指定删除共享内存。

三、共享内存注意点

1.shmctl删除共享内存

如果是多个进程装载了同一个共享内存,其中有一个进程执行了shmctl(shmid,IPC_RMID,NULL)删除了共享内存,则该段共享内存被标记为dest。如果所有进程解除了对该段共享内存的连接,即attach为0,共享内存才真正删除。

2.key值创建的共享内存标记为dest后,又有进程创建了该key值的共享内存怎么办

共享内存标记为dest后,只要attach不为0就不会真正删除。此时,连接该段共享内存的进程仍然可以互相通信。再次使用相同key值创建共享内存的进程会创建一个新的shmid的共享内存,不能与原来的key创建的共享内存通信。

3.共享内存不使用shmctl删除

共享内存不使用shmctl删除,这样即使连接数attach为0,该共享内存仍然存在,下一次连接仍然可以使用。事实上,共享内存可以通过ipcs -m shmid统一删除。

四、共享内存实现

1.代码实现

光说不练假把式,写了个小demo测试一下

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024

int main()
{
    int shmid = -1;
    int key = 10;
    int size = 1024;
    shmid = shmget(key,size,IPC_CREAT | 0666);
    if(shmid < 0)
    {
        perror("shmget");
        exit(1);
    }
    //映射
    char *ptr = NULL;
    ptr = shmat(shmid,NULL,0);//0表示共享内存可读可写
    if(ptr == (void *)-1)
    {
        perror("shmat");
        exit(1);
    }
    
    while(1)
    {
    char sym;
    printf("enter r/w/d to read or write or delete the shared memory or e to exit this process:\n");
    scanf(" %c",&sym);//%c前有空格,因为scanf会将回车保存在缓冲区,使用空格可以识别并丢弃一个结束字符,而普通的字符不受影响
    
    if(sym=='e')
    {
        break;
    }
    
    if(sym=='r')
    {
        //读数据
        if(ptr[0] != '\0')
        {
           printf("ptr = %s\n",ptr);
        } 
        continue;
    }
    if(sym=='w')
    {
        //必须要手动清空
        memset(ptr,0,size);//清空内存
        char buf[1024];
        memset(buf,0,sizeof(buf));
        printf("input the context:");
        scanf("%s",&buf);
        memcpy(ptr,buf,strlen(buf));
        continue;
    }
    if(sym=='d')
    {
        if(shmctl(shmid,IPC_RMID,NULL) == -1)
    	{
            perror("shmctl");
            exit(1);
    	}
    }
    if(sym!='r'&&sym!='w'&&sym!='d')
    {
        printf("unknown command!\n");
        continue;
    }
    }
    

    //解除共享内存映射
    if(shmdt(ptr) < 0)
    {
        perror("shmdt");
        exit(1);
    }
    return 0;
}

2.测试1

开启两个进程互相通信,权限0666,shmid为327721,大小1024,连接数2,当前用户xd
两个进程获取并连接一个共享内存

3.测试2

其中一个执行删除操作,发现并不影响所有进程继续使用共享内存,除非退出连接。

共享内存删除

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在C语言中实现共享内存需要使用操作系统提供的系统调用来创建和访问共享内存。 具体来说,需要使用以下步骤来实现共享内存: 1. 使用shmget()系统调用创建共享内存段。shmget()函数需要传入三个参数:共享内存的key,共享内存大小,以及访问权限。如果共享内存段已经存在,则可以使用shmget()函数获取共享内存段的ID。 2. 使用shmat()系统调用将共享内存段连接到进程的地址空间中。shmat()函数需要传入两个参数:共享内存段的ID和一个地址,如果该地址为空,则系统会自动分配一个地址。 3. 对共享内存段进行读写操作,使用与操作普通内存相同的方法进行访问。 4. 当进程不再需要访问共享内存段时,需要使用shmdt()系统调用将共享内存段与进程断开连接。 5. 当所有进程都断开连接并且不再需要共享内存段时,使用shmctl()系统调用删除共享内存段。 需要注意的是,共享内存的并发控制是非常重要的,需要使用互斥锁或信号量等机制来保证共享内存的正确访问。 ### 回答2: C语言可以使用System V共享内存机制来实现共享内存使用共享内存是一种在进程之间共享数据的方式,可以提高进程间通信的效率。以下是使用C语言实现共享内存的一般步骤: 1. 首先创建共享内存区域。可以使用`shmget`函数来创建共享内存,需要指定共享内存的大小、权限和标识符等参数。 2. 绑定共享内存到当前进程中。可以使用`shmat`函数将共享内存映射到当前进程的地址空间中,通过返回的指针可以访问共享内存区域。 3. 使用共享内存进行数据读写。一旦共享内存区域被映射到进程的地址空间,就可以通过指针对其进行读写操作。当多个进程共享同一块内存时,需要进行同步操作,如使用互斥锁或信号量等机制来避免数据不一致或竞态条件。 4. 分离共享内存。当不再需要使用共享内存时,可以使用`shmdt`函数将共享内存从当前进程中分离,并保留共享内存区域供其他进程使用。 5. 删除共享内存。当所有进程都不再需要使用共享内存时,可以使用`shmctl`函数来删除共享内存区域,释放资源。 需要注意的是,共享内存区域只能用于进程间通信,对于线程间通信来说,并不适用。同时,使用共享内存需要谨慎操作,确保数据的一致性和安全性。 ### 回答3: 在C语言中,可以通过使用共享内存实现不同进程之间的数据共享。下面是一个简单的示例用法: 首先,需要使用`shmget()`函数来创建一个共享内存段。该函数接受三个参数,分别是一个标识符(可以是一个整数值,通常使用IPC_PRIVATE表示),所需内存的大小(字节数),以及标志位(通常为IPC_CREAT | 0666)。 ```c int shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666); ``` 接下来,使用`shmat()`函数将共享内存段附加到当前进程的地址空间。该函数接受两个参数,即共享内存段的标识符以及访问内存段的权限(通常为0)。 ```c int* shared_memory = (int*) shmat(shmid, 0, 0); ``` 现在,可以在程序中使用`shared_memory`指针来访问共享内存。 当共享内存使用完毕后,需要使用`shmdt()`函数将其从进程中分离。 ```c shmdt(shared_memory); ``` 最后,如果不再需要该共享内存段,可以使用`shmctl()`函数进行控制。该函数的第一个参数为共享内存段的标识符,第二个参数为控制命令(通常为IPC_RMID),第三个参数为一个`struct shmid_ds*`类型的指针。 ```c shmctl(shmid, IPC_RMID, NULL); ``` 这样,就完成了在C语言中使用共享内存进行进程间数据共享的实现。需要注意的是,共享内存使用需要谨慎,因为多个进程访问共享内存时必须协调好数据的读写,防止出现数据不一致或竞争条件等问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值