通过共享内存进行通信(嵌入式学习)

通过共享内存进行通信

概念

在Linux中,共享内存是一种进程间通信(IPC)机制,允许多个进程共享同一块内存区域。这种通信方式可以提供高效的数据传输,特别适用于需要频繁交换数据的场景。
在这里插入图片描述

IO间进程通信请点击这里——》IO进程间的通信详解(嵌入式学习)

IO进程间的通信详解(嵌入式学习)《——这里
IO进程间的通信详解(嵌入式学习)《——这里这里里

要在Linux中使用共享内存,需要以下步骤:

  1. 创建共享内存段:使用shmget系统调用创建一个共享内存段。该调用需要指定共享内存标识符、内存大小和权限等参数。如果共享内存已经存在,则可以使用shmget的返回值获取该共享内存段的标识符。

  2. 连接共享内存段:使用shmat系统调用将共享内存段连接到当前进程的地址空间中。shmat需要指定共享内存段的标识符和附加选项。成功连接后,shmat将返回指向共享内存段的指针。

  3. 使用共享内存:一旦连接到共享内存段,进程可以像使用普通内存一样使用共享内存。可以读取、写入数据,进行同步操作等。

  4. 分离共享内存段:当进程不再需要使用共享内存段时,可以使用shmdt系统调用将其与当前进程分离。这将使得共享内存段不再对该进程可见,但不会删除该共享内存段。

  5. 删除共享内存段:当所有进程都不再需要使用共享内存段时,可以使用shmctl系统调用删除该共享内存段。这将释放共享内存并将其从系统中删除。

要使用共享内存,需要包含<sys/ipc.h><sys/shm.h>头文件,并链接到-lrt库。

请注意,共享内存需要进程之间进行适当的同步和互斥操作,以避免竞态条件和数据损坏。通常,使用信号量或其他同步机制来控制对共享内存的访问。

特点

共享内存在进程间通信(IPC)中具有以下特点:

  1. 高效性:共享内存提供了一种高效的数据传输方式,因为数据直接存储在共享内存中,而不需要进行进程间的数据复制。这比其他IPC机制(如管道或消息队列)更快。

  2. 大容量:共享内存可以提供较大的内存空间供多个进程共享。这使得它特别适用于需要频繁交换大量数据的场景。

  3. 实时性:由于共享内存的直接访问性质,进程可以即时地读取和写入共享内存中的数据,使得共享内存在实时应用程序中非常有用。

  4. 简单性:相对于其他IPC机制,使用共享内存进行通信相对较简单。进程可以像访问本地内存一样直接读写共享内存,无需复杂的读取或写入操作。

  5. 零拷贝:共享内存的实现方式通常使用"零拷贝"技术,即数据从一个进程的地址空间传输到另一个进程的地址空间时,避免了数据的中间复制,提高了数据传输的效率。

然而,共享内存也存在一些注意事项:

  1. 同步问题:由于多个进程可以同时访问共享内存,必须进行适当的同步操作,以避免竞态条件和数据不一致的问题。通常使用信号量、互斥锁等同步机制来控制对共享内存的访问。

  2. 生命周期管理:在使用共享内存时,需要确保在合适的时间创建、连接、分离和删除共享内存段。如果没有适当管理共享内存的生命周期,可能会导致内存泄漏或无法访问共享内存的情况。

  3. 安全性:共享内存不提供进程间的安全性保护机制,因此必须确保对共享内存的访问受到适当的权限控制,防止未经授权的进程访问共享内存。

综上所述,共享内存是一种高效、快速的进程间通信机制,适用于需要高吞吐量和实时性的应用程序。但在使用时需要注意同步、生命周期管理和安全性等方面的问题。

函数

在Linux中,可以使用以下函数来操作共享内存:

  1. int shmget(key_t key, size_t size, int shmflg)

    • 该函数创建或打开一个共享内存段。
    • 参数key是用于标识共享内存段的键值。
    • 参数size指定共享内存段的大小。
    • 参数shmflg指定一些标志选项,例如权限和创建标志。
    • 返回值是共享内存段的标识符(非负整数),如果失败则返回-1。
  2. void *shmat(int shmid, const void *shmaddr, int shmflg)

    • 该函数将共享内存段连接到当前进程的地址空间。
    • 参数shmid是共享内存段的标识符。
    • 参数shmaddr指定要连接的地址,通常设置为NULL,让内核选择一个可用地址。
    • 参数shmflg指定一些标志选项,例如读写权限和标志。
    • 返回值是指向共享内存段的指针,如果失败则返回-1
  3. int shmdt(const void *shmaddr)

    • 该函数将共享内存段与当前进程分离。
    • 参数shmaddr是要分离的共享内存段的指针。
    • 返回值为0表示成功,-1表示失败。
  4. int shmctl(int shmid, int cmd, struct shmid_ds *buf)

    • 该函数用于控制共享内存段的属性。
    • 参数shmid是共享内存段的标识符。
    • 参数cmd指定要执行的命令,如删除共享内存段。
    • 参数buf是一个指向struct shmid_ds结构的指针,用于获取或设置共享内存段的属性。
    • 返回值为0表示成功,-1表示失败。

这些函数在<sys/ipc.h><sys/shm.h>头文件中声明。要使用共享内存,您还需要链接到-lrt库。

这只是共享内存函数的基本介绍,您可以参考相关文档和教程以获取更详细的信息和示例代码。

示例代码

以下是一个简单的示例代码,展示如何使用共享内存在两个进程之间进行通信:
在这里插入图片描述

进程A(写入数据到共享内存):

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

#define SHM_SIZE 1024

int main() {
    
    
    int shmid;
    key_t key;
    char *shm_ptr;

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

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

    // 连接共享内存段到当前进程的地址空间
    shm_ptr = shmat(shmid, NULL, 0);
    if (shm_ptr == (char *)-1) {
    
    
        perror("shmat");
        exit(1);
    }

    // 写入数据到共享内存
    sprintf(shm_ptr, "Hello, shared memory!");

    // 分离共享内存段
    if (shmdt(shm_ptr) == -1) {
    
    
        perror("shmdt");
        exit(1);
    }

    return 0;
}

进程B(从共享内存中读取数据):

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

#define SHM_SIZE 1024

int main() {
    
    
    int shmid;
    key_t key;
    char *shm_ptr;

    // 获取共享内存的key
    key = ftok("/tmp", 'R');
    if (key == -1) {
    
    
        perror("ftok");
        exit(1);
    }

    // 获取共享内存段的标识符
    shmid = shmget(key, SHM_SIZE, 0666);
    if (shmid == -1) {
    
    
        perror("shmget");
        exit(1);
    }

    // 连接共享内存段到当前进程的地址空间
    shm_ptr = shmat(shmid, NULL, 0);
    if (shm_ptr == (char *)-1) {
    
    
        perror("shmat");
        exit(1);
    }

    // 从共享内存中读取数据并打印
    printf("Message from shared memory: %s\n", shm_ptr);

    // 分离共享内存段
    if (shmdt(shm_ptr) == -1) {
    
    
        perror("shmdt");
        exit(1);
    }

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

    return 0;
}

在这个示例中,进程A创建了一个大小为1024字节的共享内存段,并写入了一条消息到共享内存中。进程B通过共享内存的键获取到该共享内存段的标识符,并连接到当前进程的地址空间,然后读取共享内存中的数据并打印出来。最后,进程B从共享内存中分离,并使用shmctl函数将共享内存段删除。

请注意,在实际使用中,需要确保进程A和进程B以正确的顺序执行,以便正确地进行共享内存的创建、连接和分离。此外,需要进行适当的同步和互斥操作,以避免竞态条件和数据损坏。

编译和运行示例代码时,需要使用gcc编译器,并链接到-lrt库:

gcc processA.c -o processA -lrt
gcc processB.c -o processB -lrt

然后分别运行进程A和进程B:

./processA
./processB

进程B会输出从共享内存中读取的消息。

猜你喜欢

转载自blog.csdn.net/m0_56694518/article/details/131272217