Linux进程编程(4)共享内存

本文详细介绍了Linux中的共享内存机制,包括其用途、关键函数如ftok、shmget、shmat和shmdt的作用,以及如何通过示例代码实现父子进程间的高效数据共享和通信。
摘要由CSDN通过智能技术生成

Linux进程编程(4)共享内存


共享内存是什么

共享内存是一种进程间通信机制,允许多个进程共享同一段内存区域,以便实现高效的数据交换。这些进程可以是同一台计算机上的不同线程、父子进程,也可以是不同计算机上的网络进程。

为什么要共享内存:

  • 高效数据传输: 共享内存允许进程之间直接访问相同的内存区域,因此数据传输效率高,适用于大量数据的快速传递。
  • 避免数据拷贝: 与其他通信方式(如管道、消息队列)相比,共享内存避免了数据的多次拷贝,提高了性能。
  • 实时通信: 共享内存支持实时通信,特别适用于需要快速响应的场景。
  • 资源共享: 进程可以在共享内存中存储共享的数据结构、缓冲区等,方便多个进程访问和操作。

一、用到的函数及其作用

函数原型、返回值、作用和参数说明:

  1. key_t ftok(const char *pathname, int proj_id);

    • 返回值:若成功,返回一个键值(key_t类型),若失败,返回-1。
    • 作用:用于生成一个键值,该键值可以用于标识共享内存、消息队列等进程间通信的资源。
    • 参数:pathname是一个字符串,表示生成键值的文件路径。proj_id是一个整数,用于进一步区分不同的资源。
  2. int shmget(key_t key, size_t size, int shmflg);

    • 返回值:若成功,返回共享内存标识符(int类型);若失败,返回-1。
    • 作用:创建或获取一个共享内存段。
    • 参数:key是键值,用于标识共享内存。size是共享内存段的大小(以字节为单位)。shmflg是标志位,指定共享内存的权限和操作方式。
  3. void *shmat(int shmid, const void *shmaddr, int shmflg);

    • 返回值:若成功,返回附加的共享内存段的指针(void *类型);若失败,返回-1。
    • 作用:将共享内存段附加到进程的地址空间,使得进程可以访问共享内存中的数据。
    • 参数:shmid是共享内存标识符。shmaddr通常设置为NULL,让系统选择适当的地址。shmflg是标志位,指定共享内存的操作方式。
  4. int shmdt(const void *shmaddr);

    • 返回值:若成功,返回0;若失败,返回-1。
    • 作用:将附加的共享内存段从进程的地址空间中分离,不再能够访问共享内存的数据。
    • 参数:shmaddr是共享内存段的指针,通常是shmat()返回的指针。
  5. pid_t fork(void);

    • 返回值:若成功,返回子进程的PID(正整数)给父进程,返回0给子进程;若失败,返回-1。
    • 作用:创建一个新的子进程,子进程是父进程的复制,从调用fork()的地方开始执行。
    • 参数:无。
  6. int wait(int *status);

    • 返回值:若成功,返回结束的子进程的PID;若失败,返回-1。
    • 作用:等待任何一个子进程结束,并返回结束的子进程的PID。如果status不为NULL,会将子进程的退出状态存储在status中。
    • 参数:status是一个指向整数的指针,用于存储子进程的退出状态。
  7. int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    • 返回值:若成功,返回0;若失败,返回-1。
    • 作用:用于控制和查询共享内存的信息,如删除共享内存。
    • 参数:shmid是共享内存标识符。cmd是控制命令,可以是IPC_RMID表示删除共享内存。buf是一个指向struct shmid_ds结构的指针,用于存储共享内存的信息。

二、实现代码

1.共享内存实现代码

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

int main() {
    int shmid; // 共享内存标识符
    key_t key = ftok(".", 123); // 使用ftok生成键值,用于标识共享内存
    shmid = shmget(key, sizeof(int), IPC_CREAT | 0666); // 创建共享内存段
    int *data = (int*)shmat(shmid, NULL, 0); // 将共享内存附加到进程地址空间
    *data = 42; // 向共享内存写入数据
    pid_t pid = fork(); // 创建子进程
    if (pid < 0) {
        fprintf(stderr, "进程创建失败\n");
        return 1;
    } else if (pid == 0) { // 子进程
        printf("子进程读取共享数据:%d\n", *data);
        shmdt(data); // 分离共享内存
    } else { // 父进程
        wait(NULL); // 等待子进程结束
        printf("父进程读取共享数据:%d\n", *data);
        shmdt(data); // 分离共享内存
        shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
    }
    return 0;
}

代码逻辑和实现目的:

1.	导入必要的头文件,包括对进程、共享内存和其他系统调用函数的声明。
2.	使用ftok()函数生成一个键值,这个键值将用于标识共享内存区域。
3.	使用shmget()函数创建一个共享内存段。IPC_CREAT标志表示如果共享内存不存在则创建,0666指定了权限。
4.	使用shmat()函数将共享内存段附加到当前进程的地址空间,返回一个指向共享内存的指针。
5.	向共享内存中写入数据,将整数值42存储在共享内存中。
6.	使用fork()创建一个子进程,子进程将继承父进程的地址空间和共享内存。
7.	在父进程中,如果fork()成功,则返回子进程的进程ID(PID),如果失败则输出错误信息。
8.	在子进程中,通过共享内存指针读取并输出共享内存中的数据,然后使用shmdt()函数分离共享内存。
9.	在父进程中,使用wait()函数等待子进程结束,确保在父进程输出共享内存数据前,子进程已完成。
10.	在父进程中,再次使用shmdt()函数分离共享内存,然后使用shmctl()函数删除共享内存。

这个程序的目的是演示如何使用共享内存在父子进程之间共享数据。父进程创建了一个共享内存区域,并向其中写入了数据。然后它创建了一个子进程,子进程从共享内存中读取数据并输出。父进程等待子进程结束,然后也从共享内存中读取数据并输出。最后,父进程删除了共享内存区域,确保资源的释放。这个实例展示了进程之间如何共享数据,以及如何使用共享内存的系统调用。

2.使用共享内存进行进程间通信时的逻辑

当使用共享内存进行进程间通信时,通常的逻辑如下:

  1. 生成键值(key): 使用ftok()函数生成一个键值,这个键值将用于标识共享内存区域。这个键值需要与其他进程间通信方式(如消息队列)共享同一个键值,以确保通信能够建立。

  2. 创建共享内存: 使用shmget()函数创建一个共享内存段。为共享内存指定大小,并使用标志位来设置权限和操作方式。如果共享内存已经存在,可以通过键值获取已经创建的共享内存。

  3. 附加共享内存: 使用shmat()函数将共享内存段附加到进程的地址空间,以便进程可以访问其中的数据。需要指定共享内存标识符和一些标志。

  4. 读写共享内存: 进程可以通过访问共享内存中的数据进行读写操作。这里的读写不需要特殊的函数,直接通过指针就可以进行。

  5. 分离共享内存: 使用shmdt()函数将共享内存段从进程的地址空间中分离,不再能够访问共享内存的数据。这是一个重要的步骤,以免引发访问非法内存的问题。

  6. 删除共享内存(可选): 使用shmctl()函数删除共享内存段。这是一个可选步骤,如果不需要共享内存了,可以通过这个函数将其清理。

总体来说,共享内存的逻辑是:生成键值、创建共享内存、附加共享内存、读写共享内存、分离共享内存,以及可选的删除共享内存。这个逻辑允许进程在不同的时间、不同的空间中进行数据共享,以实现进程间的高效通信。


总结

共享内存是进程间高效通信的一种方式,适用于需要大量数据传输、实时通信和资源共享的场景。在代码中,通过共享内存,父子进程可以共享数据,通过控制函数和适当的顺序,实现了数据的交换和处理。注意要小心处理同步和互斥,以避免数据竞争等问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值