Linux系统编程之共享内存

概述

在Linux系统中,共享内存也是一种高效的进程间通信机制,允许两个或多个进程共享同一块物理内存区域。通过这种方式,不同进程可以直接访问和操作相同的数据,从而避免了数据的复制。由于数据直接在内存中共享,没有额外的数据传输过程,因此速度非常快。虽然共享内存本身提供了快速的数据交换方式,但它并不提供同步机制。这意味着,需要我们自己实现同步措施以防止竞态条件。

API接口

在Linux中,主要通过以下几个API接口来实现共享内存机制。

1、shmget:用于创建一个新的共享内存段,或获取一个已存在的共享内存段。其函数原型如下。

cpp 复制代码
int shmget(key_t key, size_t size, int shmflg);

各个参数和返回值的含义如下。

key:标识共享内存段的键值,通常使用ftok函数生成。

size:共享内存段的大小,以字节为单位。

shmflg:权限标志和创建标志(比如IPC_CREAT、IPC_EXCL等),以及访问权限。

返回值:成功时,返回共享内存标识符。失败时返回-1,可通过errno获取具体的错误代码。

2、shmat:将共享内存段连接到调用进程的地址空间。其函数原型如下。

cpp 复制代码
void *shmat(int shmid, const void *shmaddr, int shmflg);

各个参数和返回值的含义如下。

shmid:由shmget函数返回的共享内存标识符。

shmaddr:指定共享内存段应连接到的地址,通常设置为NULL,让系统自动选择。

shmflg:控制共享内存段连接的方式,如SHM_RDONLY表示只读。

返回值:成功时,返回指向共享内存段的指针。失败时返回(void *) -1,可通过errno获取具体的错误代码。

3、shmdt:将共享内存段从调用进程的地址空间分离。其函数原型如下。

cpp 复制代码
int shmdt(const void *shmaddr);

各个参数和返回值的含义如下。

shmaddr:由shmat返回的地址。

返回值:成功时,返回0。失败时返回-1,可通过errno获取具体的错误代码。

4、shmctl:执行多种控制操作,如获取共享内存段的状态、设置共享内存段的状态、删除共享内存段等。其函数原型如下。

cpp 复制代码
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

各个参数和返回值的含义如下。

shmid:由shmget函数返回的共享内存标识符。

cmd:命令ID,比如,IPC_STAT表示获取状态、IPC_SET表示设置状态、IPC_RMID表示移除段。

buf:根据命令不同,可能需要提供一个指向struct shmid_ds结构体的指针。

返回值:成功时,返回0。失败时返回-1,可通过errno获取具体的错误代码。

实战代码

在下面的实战代码中,我们使用共享内存机制来创建、写入和分离一个共享内存段。

首先,通过调用ftok函数并传入一个路径名和一个项目ID,生成一个唯一的键值,该键值用于后续标识共享内存段。然后,利用shmget函数根据这个键值创建一个新的共享内存段。这里指定共享内存的大小为1024字节,并设置了权限标志,以确保创建时赋予读写权限给所有用户。

一旦成功获得共享内存段的标识符shmid,我们便通过shmat函数将这个共享内存段连接到当前进程的地址空间中。shmat会返回一个指向共享内存起始位置的指针,随后,我们使用strcpy函数将字符串复制到该指针中。

最后,我们调用shmdt函数将共享内存段从当前进程的地址空间中进行了分离。

cpp 复制代码
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>

int main()
{
    // 创建唯一的键
    key_t key = ftok("shmfile", 66);
    
    // 创建共享内存段
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    
    // 连接共享内存段
    char *pszBuffer = (char*)shmat(shmid, (void*)0, 0);
    strcpy(pszBuffer, "Hello, Hope_Wisdom");
    printf("Data written in memory: %s\n", pszBuffer);

    // 分离共享内存段
    shmdt(pszBuffer);
    return 0;
}

为了与上面的进程相配合,我们实现了下面的进程,使用共享内存机制来获取、读取和管理一个共享内存段。

首先,我们调用shmget函数根据键值获取一个已经存在的共享内存段。这里指定共享内存的大小为1024字节,并设置了权限标志,以确保创建时赋予读写权限给所有用户。

一旦成功获得共享内存段的标识符shmid,我们便通过shmat函数将这个共享内存段连接到当前进程的地址空间中。shmat会返回一个指向共享内存起始位置的指针,随后,我们直接尝试从该指针读取数据并打印出来。

cpp 复制代码
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

int main()
{
    // 创建唯一的键
    key_t key = ftok("shmfile", 66);
    
    // 获取共享内存段ID
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    
    // 连接共享内存段
    char *pszBuffer = (char*)shmat(shmid, (void*)0, 0);
    printf("Data read from memory: %s\n", pszBuffer);

    // 分离共享内存段
    shmdt(pszBuffer);
    
    // 删除共享内存段
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
相关推荐
wulalalalalalalal4 分钟前
Linux 内网服务器通过代理访问外网
linux·运维·服务器
C_心欲无痕6 分钟前
ts - 模板字面量类型与 `keyof` 的魔法组合:`keyof T & `on${string}`使用
linux·运维·开发语言·前端·ubuntu·typescript
fy zs9 分钟前
网络编程套接字
linux·服务器·网络·c++
望眼欲穿的程序猿15 分钟前
基于Linux&MacOS 开发Ai8051U
linux·运维·macos
Bigbig.19 分钟前
驱动工程师面试题 - 操作系统1
linux·开发语言·面试·硬件架构
oMcLin35 分钟前
如何在 CentOS Stream 9 上配置并优化 PostgreSQL 15,支持高并发的数据插入与快速查询?
linux·postgresql·centos
柏木乃一36 分钟前
进程(11)进程替换函数详解
linux·服务器·c++·操作系统·exec
ben9518chen42 分钟前
Linux文件系统基础
linux·服务器·php
晴天¥1 小时前
计算机网络-Linux配置-DNS解析/为什么会出现ping: www.baidu.com: 未知的名称或服务
linux·运维·计算机网络
代码游侠1 小时前
应用——Linux FrameBuffer图形显示与多线程消息系统项目
linux·运维·服务器·开发语言·前端·算法