📜  共享内存段介绍

📅  最后修改于: 2021-09-27 22:44:36             🧑  作者: Mango

共享内存段介绍:
可访问的最快 IPC 类型是共享内存。将内存映射到共享内存区域的进程的地址空间后,没有内核参与进程间的数据传输。但是,通常需要在共享内存区域中保存数据和从共享内存区域检索数据的进程之间进行某种类型的同步。互斥体、条件变量、读写锁、记录锁和信号量都在本系列的第 3 部分中进行了探讨。
考虑我们用来演示各种形式的消息传递的客户端-服务器文件复制应用程序中的典型阶段。

  • 输入文件由服务器读取。内核将文件中的数据读入其内存,然后将其复制到进程中。
  • 服务器使用管道、FIFO 或消息队列将此数据写入消息。

这些类型的 IPC 通常需要从进程到内核的数据传输。
在大多数情况下,需要四份数据副本。此外,这四个副本是在内核和进程之间进行的,这通常是一个成本高昂的副本(比在内核内或单个进程内复制数据成本更高)。客户端和服务器之间通过内核的数据传输如图 1 所示。

图1。

各种类型的 IPC(管道、FIFO 和消息队列)的难点在于信息必须通过内核才能让两个进程进行通信。

通过允许两个或更多进程共享内存空间,共享内存提供了一种解决方法。当然,进程必须协同工作以协调或同步它们对共享内存的使用。

这种同步可以使用任何一种策略来完成,以下是客户端-服务器示例的阶段:

  • 服务器使用信号量来访问共享内存对象。
  • 服务器从输入文件加载共享内存对象。数据缓冲区的地址是读取的第二个参数,指向共享内存对象。
  • 读取完成后,服务器向客户端发送信号量消息。
  • 来自共享内存对象的数据由客户端写入输出文件。

创建并初始化一个信号量:
我们建立并初始化一个信号量来保护我们认为是共享的变量(全局计数)。这个信号量是不必要的,因为这个假设是不正确的。注意我们如何执行 sem unlink 从系统中删除信号量名称;然而,虽然这会删除路径名,但它对已经打开的信号量没有影响。我们这样做是为了即使程序崩溃,路径名也会从文件系统中删除。

设置无缓冲标准输出和 fork :
因为父级和子级都将写入标准输出,所以我们让它无缓冲。因此,两个进程的输出不会交错。父级和子级都运行一个循环,将计数器增加设定的次数,仅在保持信号量时增加变量。

C
#include 
#include 
#define GEEKSNAME "mysem"
int counter = 0;
int main(int argc, char** argv)
{
    int i, nloop;
    sem_t* mutex;
    if (argc != 2)
        err_quit("usage: incr1 <#loops>");
    nloop = atoi(argv[1]);
    /* unlink semaphore */
    mutex = Sem_open(Px_ipc_name(GEEKSNAME),
                     O_CREAT | O_EXCL, FILE_MODE, 1);
    Sem_unlink(Px_ipc_name(GEEKSNAME));
    setbuf(stdout, NULL); /* stdout is unbuffered */
    if (Fork() == 0) { /* child */
        for (i = 0; i < nloop; i++) {
            Sem_wait(mutex);
            printf("child: %d\n", counter++);
            Sem_post(mutex);
        }
        exit(0);
    }
    /* owner */
    for (i = 0; i < nloop; i++) {
        Sem_wait(mutex);
        printf("parent: %d\n", counter++);
        Sem_post(mutex);
    }
    exit(0);
}


可以看出,这两个进程都有自己的全局计数副本。每个变量都以 0 的值开始,然后增加它自己的副本。

结论 :
由于共享内存中数据的一份副本可供共享内存的所有线程或进程使用,因此共享内存是可访问的最快 IPC 类型。但是,为了协调共享内存的众多线程或进程,通常需要某种类型的同步。

因为这是一种跨相关或不相关进程传输内存的技术,本章重点介绍了 mMap函数和常规文件到内存的映射。我们不再需要读取、写入或寻求访问已被内存映射的文件;相反,我们只是获取或保存已被 mMap 映射到文件的内存区域。