栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

SystemV 共享内存

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SystemV 共享内存

SystemV 共享内存
  • 进程间通信(interprocess communication——IPC)允许两个独立的进程进行数据交换,即相互发送数据和接收数据。进程间通信有两种基本模型:共享内存和消息传递。在共享内存模型中,建立了一个由协作进程共享的内存区域,然后,进程可以通过向共享区域读写数据来交换信息。在消息传递模型中,通信通过协作进程之间交换的消息进行。共享内存可能比消息传递更快,因为消息传递通常需要系统调用来实现,因此需要更耗时的内核干预任务。消息传递对于交换少量数据很有用,因为不需要避免冲突。在共享内存系统中,仅在建立共享内存区域时才需要系统调用。一旦建立了共享内存,所有访问都被视为例行内存访问,不需要内核的帮助。

  • 通过系统调用,将多个进程地址空间的部分区域映射到同一份物理内存,从而形成共享内存。共享内存具有最大的通信速度和便利性,因为它可以在计算机中以内存传输速度完成通信。然而,共享内存在多进程访问的同步和互斥方面存在问题,需程序员自行保证数据安全。

  • 进程运行结束,系统创建的IPC资源并不会释放,它的生命周期由内核决定。可以通过以下命令查看并手动释放:

    [test@VM-12-4-centos SystemVIPC]$ ipcs -m
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status       # perms文件权限
    0x66010da7 0          test       664        4096       0                       
    
    [test@VM-12-4-centos SystemVIPC]$ ipcrm -m 0
    [test@VM-12-4-centos SystemVIPC]$ ipcs -m
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status 
    
  • SystemV 共享内存的系统调用:

  • 分配共享内存
#include 
#include 
int shmget(key_t key, size_t size, int shmflg);

key:必须是IPC独立私有的值。可以通过ftok()生成

#include 
#include 
key_t ftok(const char *pathname, int proj_id);

失败返回-1;成功返回System V IPC key。当pathname和proj_id相同时,生成的key是相同的。

size:系统给共享内存分配的大小实际是PAGE_SIZE(4Kb)的整数倍。

shmflg: IPC_CREAT :存在则获取,不存在则创建一块新的内存区域; IPC_EXCL:与创建选项一起使用,若已经存在则创建失败,保证创建的共享内存是第一次创建的。

返回值:成功创建返回共享内存的ID;失败则返回-1。

  • 删除共享内存
#include 
#include 
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

cmd:IPC_RMID:删除共享内存

buf:shmid的data struct,用来描述共享内存的属性

  • 将共享内存与进程的虚拟地址空间进行挂接
#include 
#include 
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:shmget()的返回值,为共享内存的ID(类似于数组下标)

shmaddr:虚拟地址空间的地址,设置为NULL会由操作系统进行分配。

shmflg:设0由操作系统管理。

返回值:成功返回共享内存的段地址——虚拟地址。

  • 将共享内存与进程解挂接
int shmdt(const void *shmaddr);

shmaddr:shmat()的返回值。

下面是一段例程说明SystemV共享内存的使用:

  • SharedPath.h
#pragma once

#define PipeFilePath "PipeFile"
#define IPC_ID 0x1666
  • server.c
#include 
#include 
#include 
#include 
#include "SharedPath.h"
#include 
#include 

int main()
{

    key_t KeyVal = ftok(PipeFilePath, IPC_ID);
    if(KeyVal == -1)
    {
        perror("ftok failedn");
        exit(-1);
    }

    //int id = shmget(KeyVal, 4096, IPC_CREAT | IPC_EXCL | 0664); 
    int id = shmget(KeyVal, 4096, IPC_CREAT | 0664); //在物理内存中开辟了一段共享空间
    if(id < 0)
    {
        perror("shmget failedn");
        exit(-2);
    }

    char* Virtualaddr = (char*)shmat(id, NULL, 0);
    
    // ************共享内存使用****************
    while(1)
    {
        printf("%sn", Virtualaddr); //读取
        fflush(stdout);
        sleep(1);
        if(Virtualaddr == NULL)
        {
            break;
        }
    }
	//***************************************
    shmdt(Virtualaddr);
    shmctl(id, IPC_RMID, NULL); //释放共享内存空间
    return 0;
}
  • client.c
#include 
#include 
#include 
#include 
#include "SharedPath.h"
#include 
#include 

int main()
{

    key_t KeyVal = ftok(PipeFilePath, IPC_ID);
    if(KeyVal == -1)
    {
        perror("ftok failedn");
        exit(-1);
    }

    int id = shmget(KeyVal, 4096, IPC_CREAT); //获取已存在的IPC ID。
    if(id < 0)
    {
        perror("shmget failedn");
        exit(-2);
    }
    char* Virtualaddr = (char*)shmat(id, NULL, 0);
    
    // ************共享内存使用****************
    int i = 0;
    while(1)
    {
        for(i = 0; i < 10; i++)
        {
            Virtualaddr[i] = 'a'; 
            sleep(5);
        }
        Virtualaddr[i] = 'n'; 
        Virtualaddr[i + 1] = ''; 
    }
	//***************************************
    shmdt(Virtualaddr);
    return 0;
}
  • Makefile
.PHONY:all
all:client server
client:client.c
	gcc -o $@ $^

server:server.c
	gcc -o $@ $^

.PHONY:clean
clean:
	rm -f client server
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/964996.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号