b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

共享内存是Unix下的多进程之间的通信方法

电脑杂谈  发布时间:2021-06-03 15:02:51  来源:网络整理

共享内存是指在多处理器计算机系统中可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问内存,因此需要对内存进行缓存(Cache)。任何缓存数据更新后,因为其他处理器可能也需要访问,所以需要立即更新共享内存,否则不同的处理器可能使用不同的数据。共享内存是Unix下多进程间的一种通信方式。这种方法通常用于一个程序的多个进程之间的通信。事实上,多个程序也可以通过共享内存来传递信息。

1.共享内存概述

共享内存是进程间通信最简单的方式之一。共享内存允许两个或多个进程访问同一块内存,就像 malloc() 函数将指向同一物理内存区域的指针返回给不同进程一样。当一个进程改变了这个地址的内容时,其他进程就会知道这个变化。

内存共享技术

如上图所述,共享内存实际上是一个进程通过调用shmget(SharedMemoryGET获取共享内存)分配一个共享内存块,然后各个进程使用shmat(SharedMemoryAttach绑定到共享内存块)来绑定进程的逻辑虚拟地址空间指向共享内存块。所有需要访问此共享内存块的后续进程都必须将此共享内存绑定到自己的地址空间。当进程向共享内存块写入数据时,所有共享该内存区域的进程都可以看到内容。

共享内存的特点:

共享内存是进程间共享数据的最快方式。当一个进程向共享内存区写入数据时,所有共享该内存区的进程都可以立即看到内容。使用共享内存时,重要的是要注意在多个进程之间访问给定内存区域的互斥。如果一个进程正在向共享内存区域写入数据,则在完成此步骤之前,其他进程不应读取或写入这些数据。 2.共享内存通信

由于所有进程共享同一个内存,共享内存在各种进程间通信方式中效率最高。访问共享内存区与访问进程的唯一内存区一样快,不需要通过系统调用或其他需要切入内核的进程来完成。也避免了各种不必要的数据重复。

因为系统内核不会同步访问共享内存,所以必须提供自己的同步措施。例如,在写入数据之前,不允许进程从共享内存中读取信息,不允许两个进程同时向同一个共享内存地址写入数据。解决这些问题的常用方法是使用信号量进行同步。

3.Memory 共享内存模型

要使用一块共享内存,进程必须先分配它。随后需要访问此共享内存块的每个进程都必须将此共享内存绑定到自己的地址空间。当通信完成后,所有进程都会离开共享内存,一个进程会释放共享内存块。了解 Linux 系统内存模型有助于解释这个绑定过程。在 Linux 系统中,每个进程的虚拟内存被分成许多页。这些内存页包含实际数据。每个进程都维护着从内存地址到虚拟内存页的映射关系。虽然每个进程都有自己的内存地址,但是不同的进程可以同时将同一个内存页映射到自己的地址空间中,从而达到共享内存的目的。

分配一个新的共享内存块将创建一个新的内存页。因为所有进程都希望共享对同一内存的访问,所以只有一个进程应该创建一个新的共享内存。再次分配现有内存块不会创建新页面,而只会返回标识内存块的标识符。如果一个进程需要使用这个共享内存块,它首先需要将它绑定到自己的地址空间。这将创建从进程本身的虚拟地址到共享页面的映射关系。当共享内存的使用结束时,该映射关系将被删除。当没有进程需要再使用这个共享内存块时,必须有一个(并且只有一个)进程负责释放共享内存页。

4.共享内存操作4.1共享内存分配

进程通过调用shmget(Shared Memory GET)来分配一个共享内存块。

这个函数的第一个参数是一个key,用来标识共享内存块。不相关的进程可以通过指定相同的键来访问相同的共享内存块。不幸的是,其他程序也可能为自己的共享内存分配选择与键值相同的特定值,从而导致冲突。使用特殊常量 IPC_PRIVATE 作为键值可以保证系统创建一个全新的共享内存块。此函数的第二个参数指定请求的内存块的大小。因为这些内存块是以页为单位分配的,所以实际分配的内存块大小会被扩展为页大小的整数倍。第三个参数是一组标志,shmget是通过特定常量的按位或运算来执行的。

所需的头文件:

#include

#include

int shmget(key_t key, size_t size,int shmflg);

功能:

创建或打开共享内存区域。

参数:

服务器集群 内存共享_服务器集群内存共享_内存共享技术

key:进程间通信的key值,ftok()的返回值。

size:共享存储段的长度(字节)。

shmflg:标识函数的行为和共享内存的权限,其值如下:

IPC_CREAT:不存在则创建

IPC_EXCL:如果已经存在,返回失败

位或权限位:在共享内存位或权限位之后,可以设置共享内存的访问权限。格式与open()函数的mode_t相同(open()的使用请点此链接),但没有使用可执行权限。

返回值:

成功:共享内存标识符。

失败:-1。

4.2.共享内存映射

为了让进程能够访问一块共享内存,进程必须首先调用shmat(Shared Memory Attach,绑定到共享内存)。将 shmget 返回的共享内存标识符 SHID 作为第一个参数传递给该函数。该函数的第二个参数是指向要用于映射共享内存块的进程的虚拟内存地址的指针;如果指定 NULL,Linux 将自动选择合适的地址进行映射。第三个参数是一个标志位,

所需的头文件:

#include

#include

void *shmat(int shmid, const void *shmaddr, int shmflg);

功能:

将共享内存段映射到调用进程的数据段。简单理解,让进程与共享内存建立连接,让进程的一个指针指向共享内存。

参数:

shmid:共享内存标识符,shmget()的返回值。

shmaddr:共享内存映射地址(如果为NULL,系统会自动指定),建议为NULL。

shmflg:共享内存段的访问权限和映射条件(一般为0),具体取值如下:

0:共享内存有读写权限。

服务器集群内存共享_服务器集群 内存共享_内存共享技术

SHM_RDONLY:只读。

SHM_RND:(仅当shmaddr不为空时有效)

返回值:

成功:共享内存段映射地址(相当于这个指针指向这个共享内存)

失败:-1

4.3.去掉共享内存的映射

当一个进程不再使用共享内存块时,它应该通过调用 shmdt(共享内存分离)函数与共享内存块分离。如果释放内存块的进程是最后一个使用该内存块的进程,则该内存块将被删除。调用 exit 或任何 exec 系列函数将自动导致进程离开共享内存块。

所需的头文件:

#include

#include

int shmdt(const void *shmaddr);

功能:

将共享内存与当前进程分离(只是断开连接并不会删除共享内存,相当于让之前指向此共享内存的指针不再指向它)。

参数:

shmaddr:共享内存映射地址。

返回值:

成功:0

失败:-1

4.4.共享内存控制

所需的头文件:

#include

#include

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

功能:

共享内存属性的控制。

参数:

shmid:共享内存标识符。

cmd:功能控件,其值如下:

IPC_RMID:删除。 (常用)

IPC_SET:设置shmid_ds参数相当于将共享内存的原始属性值替换为buf中的属性值。

IPC_STAT:保存shmid_ds参数,将共享内存的原始属性值备份到buf中。

SHM_LOCK:锁定共享内存段(超级用户)。

SHM_UNLOCK:解锁共享内存段。

SHM_LOCK 用于锁定内存和禁止内存交换。这并不意味着其他进程被锁定后就不能访问共享内存。它的真正含义是:被锁定的内存不允许交换到虚拟内存。这样做的好处是共享内存永远在内存中,从而提高了程序的性能。

buf:shmid_ds 数据类型地址(具体类型请点击此链接),用于存储或修改共享内存的属性。

返回值:

成功:0

失败:-1

4.实战例子

举个例子:创建两个进程,在进程A中创建共享内存,向其中写入数据,通过进程B从共享内存中读取数据。

编写代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUFSZ 512
int main(int argc, char *argv[])
{
    int shmid;
    int ret;
    key_t key;
    char *shmadd;
    
    //创建key值
    key = ftok("../", 2015);
    if(key == -1)
    {
        perror("ftok");
    }
    
    //创建共享内存
    shmid = shmget(key, BUFSZ, IPC_CREAT|0666);    
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    
    //映射
    shmadd = shmat(shmid, NULL, 0);
    if(shmadd < 0)
    {
        perror("shmat");
        _exit(-1);
    }
    
    //拷贝数据至共享内存区
    printf("copy data to shared-memory\n");
    bzero(shmadd, BUFSZ); // 共享内存清空
    strcpy(shmadd, "how are you, lh\n");
    
    return 0;
}

阅读代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUFSZ 512
int main(int argc, char *argv[])
{
    int shmid;
    int ret;
    key_t key;
    char *shmadd;
    
    //创建key值
    key = ftok("../", 2015);
    if(key == -1)
    {
        perror("ftok");
    }
    
    system("ipcs -m"); //查看共享内存
    
    //打开共享内存
    shmid = shmget(key, BUFSZ, IPC_CREAT|0666);
    if(shmid < 0)
    {
        perror("shmget");
        exit(-1);
    }
    
    //映射
    shmadd = shmat(shmid, NULL, 0);
    if(shmadd < 0)
    {
        perror("shmat");
        exit(-1);
    }
    
    //读共享内存区数据
    printf("data = [%s]\n", shmadd);
    
    //分离共享内存和当前进程
    ret = shmdt(shmadd);
    if(ret < 0)
    {
        perror("shmdt");
        exit(1);
    }
    else
    {
        printf("deleted shared-memory\n");
    }
    
    //删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    
    system("ipcs -m"); //查看共享内存
    
    return 0;
}


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-380155-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...