深入探索共享内存

一、什么是共享内存 

        共享内存技术是一种高效的进程间通信方式,允许多个进程共享同一块物理内存区域,从而实现快速的数据交换和共享。通过映射共享内存到各个进程的地址空间,进程可以直接访问共享数据,避免了复制和消息传递的开销,适用于需要高性能和低延迟的应用场景。

共享内存的实现依赖于操作系统提供的机制,通常包括以下步骤:

  • 创建共享内存:首先,一个进程请求操作系统分配一块共享内存区域。这可以通过系统调用(如shmget)来完成,需要指定共享内存的大小和权限等参数。
  • 映射共享内存:每个请求使用共享内存的进程都需要将共享内存映射到自己的地址空间中,以便能够访问这块内存区域。这可以通过系统调用(如shmat)来完成,映射成功后,进程可以像访问普通内存一样使用共享内存。
  • 访问共享内存:一旦共享内存映射到进程的地址空间,多个进程就可以通过读写共享内存来进行通信。操作系统会负责管理共享内存的访问权限和同步。
  • 撤销共享内存映射:当进程不再需要共享内存时,可以使用系统调用(如shmdt)将共享内存从进程的地址空间中撤销映射。
  • 删除共享内存:如果共享内存不再需要,可以使用系统调用(如shmctl)来删除共享内存,释放相关资源。

二、实现方法 

在Linux系统中,共享内存的主要实现步骤如下:

  • 创建共享内存:使用 shmget 系统调用创建一个共享内存标识符,指定大小和权限。
  • 映射共享内存:使用 shmat 系统调用将共享内存附加到进程的地址空间。
  • 访问共享内存:通过指针访问共享内存,进行数据读写操作。
  • 撤销共享内存映射:使用 shmdt 系统调用将共享内存从进程的地址空间分离。
  • 删除共享内存:使用 shmctl 系统调用删除共享内存标识符,释放相关资源。

示例

创建读进程和写进程,通过共享内存传递数据。

进程1:写入共享内存

负责创建共享内存,将字符串 “Hello from process 1” 写入共享内存,然后分离共享内存。

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

#define SHM_SIZE 1024  // 共享内存大小

int main() {
    key_t key = ftok("/tmp/shared_memory", 'R');  // 生成共享内存的key
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    int shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);  // 创建共享内存
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    char *shmaddr = shmat(shmid, NULL, 0);  // 映射共享内存
    if (shmaddr == (char *) -1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    strcpy(shmaddr, "Hello from process 1");  // 写入共享内存

    printf("Process 1 wrote: %s\n", shmaddr);

    shmdt(shmaddr);  // 分离共享内存

    return 0;
}

进程2:读取共享内存

通过相同的 key 打开进程1创建的共享内存,读取其中的数据并输出,然后分离共享内存。

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

#define SHM_SIZE 1024  // 共享内存大小

int main() {
    key_t key = ftok("/tmp/shared_memory", 'R');  // 使用同一个key打开共享内存
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    int shmid = shmget(key, SHM_SIZE, 0666);  // 打开共享内存
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }
    char *shmaddr = shmat(shmid, NULL, 0);  // 映射共享内存
    if (shmaddr == (char *) -1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }

    printf("Process 2 read: %s\n", shmaddr);  // 读取共享内存

    shmdt(shmaddr);  // 分离共享内存

    return 0;
}

需要注意

  • 进程同步:共享内存本身不提供进程间的同步机制,因此在多进程访问时需要结合信号量、互斥锁等机制来确保数据的正确读写。

  • 资源管理:共享内存在使用完毕后需要适当地进行管理,包括映射、分离和删除操作,以避免资源泄漏和系统资源耗尽。

通过合理使用共享内存和同步机制,可以在多个进程之间高效地实现数据共享和通信,是Unix/Linux系统中常用的进程间通信方式之一。

三、删除与释放 

  • 显式删除:当不再需要共享内存时,可以显式地调用系统函数进行删除。在Unix/Linux系统中,可以使用 shmctl 函数,指定 IPC_RMID 命令来删除共享内存标识符,释放相关资源。

  • 进程结束:如果一个进程附加(attach)了共享内存但没有显式分离(detach),通常在进程终止时,操作系统会自动将共享内存从进程的地址空间中分离(detach),但不会删除共享内存本身。其他进程仍然可以访问这块共享内存。

  • 系统关闭:在系统关闭时,所有共享内存和其他 IPC 资源会被释放,操作系统负责清理所有未释放的资源。

  • 手动清理:如果进程异常终止或者没有正确处理共享内存的释放,可能会导致共享内存资源泄漏。为了避免这种情况,程序员应该确保在不再需要共享内存时,显式地进行释放操作。

示例:

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

#define SHM_SIZE 1024  // 共享内存大小

int main() {
    key_t key = ftok("/tmp/shared_memory", 'R');  // 使用相同的key获取共享内存
    if (key == -1) {
        perror("ftok");
        exit(EXIT_FAILURE);
    }

    int shmid = shmget(key, SHM_SIZE, 0666 | IPC_CREAT);  // 创建共享内存
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    // 使用共享内存...

    // 删除共享内存
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
       perror("shmctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}

 进程通过 shmctl(shmid, IPC_RMID, NULL) 删除了共享内存标识符 shmid 所代表的共享内存。一旦共享内存被删除,它将不再存在于系统中,其他进程也无法再访问该共享内存。

注意事项

  • 正确性和安全性:确保在不再需要共享内存时及时进行删除操作,以避免资源泄漏和系统资源的浪费。

  • 进程通信:在多进程通信的场景中,共享内存的使用需要结合合适的同步机制(如信号量、互斥锁)来保证数据的一致性和安全性。

四、经典应用 

共享内存在操作系统和应用程序中有许多经典的使用,主要用于提高进程间通信的效率和灵活性,比如:

  • 多进程协作:生产者-消费者问题,多个生产者进程向共享内存中写入数据,多个消费者进程从共享内存中读取数据。共享内存提供了高效的数据交换方式,避免了频繁的进程间消息传递开销,例如用于处理大量实时数据的系统。

  • 图像处理:并行处理,多个进程或线程可以共享一个图像的像素数据,每个进程负责不同部分的处理,如滤波、缩放或特征提取。共享内存允许它们直接访问图像数据,从而加快处理速度。

  • 数据库管理:数据库缓存,数据库系统可以使用共享内存来实现高速缓存,多个数据库进程可以共享同一块内存作为缓存区域,提高数据检索和更新的速度。

  • 游戏开发:多进程协作,在多人在线游戏中,服务器和多个客户端之间使用共享内存来传输实时游戏状态数据,如玩家位置、物体坐标等,以实现快速响应和同步。

  • 并行计算:在科学计算领域,使用共享内存可以实现多个计算节点共享大规模数据集,如地震模拟、天气预测等复杂计算任务,提高计算效率和并行度。

  • 实时系统:主要是对实时数据传输的要求场合,在需要高实时性的系统中,如工业控制系统、航空航天系统,共享内存用于快速传输传感器数据、控制指令等,以实现及时的反应和处理。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值