<Linux系统复习>共享内存

一、本章重点

1、什么是共享内存?

2、使用共享内存

3、共享内存的性质

4、基于管道+共享内存的cs通信

5、System V标准的三种进程通信

01 什么是共享内存?

1、一段用来进程通信的内核缓冲区

2、图解:

 3、系统可以创建多个共享内存,如何确保两个进程看到同一个共享内存?

 通过相同的key可以看到同一个共享内存,这个key是用来创建或获取共享内存的,用户可以传相同的key给两个进程,进程一用来创建一个全新的共享内存,进程二则用来获取进程一创建的共享内存,这样进程一和进程二就能看到相同的进程。

 4、两个进程要使用共享内存需要先做好以下几件事

①创建/获取共享内存

②关联共享内存:即地址空间和物理内存建立映射关系

③去关联:去映射关系

④删除共享内存:因为共享内存的生命周期是随操作系统的,如果不主动删除,需要重启操作系统才会删除。

02 使用共享内存

1、shmget:用于创建共享内存

 key:在系统层面上标定共享内存的唯一性,该值存放在共享内存的数据结构中,该值可以随意设置,但一般都是用ftok函数获取一个key值。

size:设置共享内存的大小,一般设置为4k的整数倍,因为操作系统在分配空间时是以4k对齐的。如果你设置为4097字节,它实际给了你8k的大小。

shmflg:设置你是要创建一个新的共享内存,还是获取一个旧的共享内存。

创建一个全新的共享内存:IPC_CREAT | IPC_EXEC | 0666

IPC_CREAT:创建一个共享内存,如果存在则返回旧的共享内存。

IPC_EXEC:不单独使用,IPC_CREAT | IPC_EXEC表示,创建一个共享内存,如果存在则出错返回,也就是说创建一个全新的共享内存。

0666:设置要创建的共享内存的权限。

返回值:出错返回-1.

 

2、ftok:获取key值

 pathname:路径名,可以随意设置,我一般用pwd的输出值。

 proj_id:项目id,随意设置。

 ftok是通过pathname和proj_id的某种算法生成一个唯一的key值。 

 返回值:失败返回-1

 

3、shmctl:完成共享内存的控制,常用于删除共享内存

 shmid:用户层标定共享内存唯一性的id。

 cmd:设置为IPC_RMID,表示你要删除共享内存。

 buf:与共享内存的结构体有关,删除设置为nullptr。

4、shmat:建立映射关系

 shmid:用户层标定共享内存唯一性的id。

 shmaddr:设置你要映射到地址空间的哪个区域,一般设置为nullptr,让操作系统帮你自动映射。

 shmflg:设置你要对共享内存进行只读还是读写,一般设置为0,代表读写。

 返回值:返回一段共享区的首地址,和malloc一样,malloc返回的是堆区的首地址。

5、shmdt:去掉映射关系

shmaddr:shmat的返回值,代表你要去关联的共享区。这个函数与free差不多。

6、写一个简单的基于共享内存的cs通信。

 

comm.hpp

#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<cstdlib>
#include<unistd.h>

#define PATH "/home/ds/vscode"
#define PROJID 0x1334
#define SIZE 4096 //建议为4k的整数倍

client.cc

#include"comm.hpp"
using namespace std;

int main()
{
    key_t k = ftok(PATH,PROJID);
    if(k < 0)
    {
        cerr<<"ftok error"<<endl;
    }

    umask(0);
    int shmid = shmget(k,SIZE,IPC_CREAT);//获取共享内存
    
    char* str = (char*)shmat(shmid,nullptr,0);//关联
    //使用共享内存
    int cnt = 0;
    while(cnt < 26)
    {
        sleep(1);
        str[cnt] = 'A' + cnt;
        cnt++;
        str[cnt] = '\0';
    }

    shmdt(str);//去关联
    return 0;
}

server.cc

#include"comm.hpp"
using namespace std;

int main()
{
    key_t k = ftok((const char*)PATH,PROJID);
    if(k < 0)
    {
        cerr<<"ftok error"<<endl;
        exit(1);
    }

    umask(0);
    int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//创建一个全新的共享内存
    if(shmid < 0)
    {
        cerr<<"shmget error"<<endl;
    }
    char* str = (char*)shmat(shmid,nullptr,0);//关联
    //使用共享内存
    while(true)
    {
        sleep(1);
        cout<<"."<<str<<endl;
    }
    shmdt(str);//去关联
    shmctl(shmid,IPC_RMID,nullptr);//删除共享内存
    return 0;
}

makefile

.PHONY:all
all:client server

client:client.cc
	g++ -o $@ $^ -std=c++11

server:server.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f client server

7、查看创建的共享内存

 key:在系统层面标定共享内存的唯一性

 shmid:在用户层面标定共享内存的唯一性

 owner:拥有者

 perms:访问权限

 bytes:共享内存的大小

 nattch:关联数/挂接数

 status:状态

8、删除创建的共享内存

可以用系统调用删除:shmctl

也可以用指令删除:ipcrm -m [shmid]

03 共享内存的性质

 1、所有进程通信中,共享内存速度最快,因为没有访问控制,数据拷贝次数少。

 2、没有访问控制(同步和互斥)

 3、面向数据流

 4、生命周期随内核

 5、全双工

04基于管道+共享内存的cs通信

设计思路:管道用来访问控制,共享内存来传输数据。

 client.cc

#include"comm.hpp"
using namespace std;

int main()
{
    key_t k = ftok(PATH,PROJID);
    if(k < 0)
    {
        cerr<<"ftok error"<<endl;
    }

    umask(0);
    int shmid = shmget(k,SIZE,IPC_CREAT);//获取共享内存
    
    char* str = (char*)shmat(shmid,nullptr,0);//关联
    //使用共享内存
    int fd = open(PATH_PIPE,O_WRONLY);
    while(true)
    {
        cout<<"please Enter# ";
        fflush(stdout);
        ssize_t s = read(0,str,sizeof(char)*4096);
        if(s < 0)
        {
            cerr<<"read error"<<endl;
            exit(2);
        }
        else if(s == 0)
        {
            cerr<<"写端关闭"<<endl;
            exit(0);
        }
        else
        {
             str[s-1] = '\0';
        }
        write(fd,&s,sizeof(int));//告诉server已经写好了数据
    }


    // int cnt = 0;
    // while(cnt < 26)
    // {
    //     sleep(1);
    //     str[cnt] = 'A' + cnt;
    //     cnt++;
    //     str[cnt] = '\0';
    // }
    close(fd);
    shmdt(str);//去关联
    return 0;
}

 server.cc

#include"comm.hpp"
using namespace std;

int main()
{
    key_t k = ftok((const char*)PATH,PROJID);
    if(k < 0)
    {
        cerr<<"ftok error"<<endl;
        exit(1);
    }

    umask(0);
    int shmid = shmget(k,SIZE,IPC_CREAT | IPC_EXCL | 0666);//创建一个全新的共享内存
    if(shmid < 0)
    {
        cerr<<"shmget error"<<endl;
    }
    char* str = (char*)shmat(shmid,nullptr,0);//关联

    if(mkfifo(PATH_PIPE,0666)!=0)
    {
        cerr<<"mkfifo error"<<endl;
    }

    int fd = open(PATH_PIPE,O_RDONLY);

    //使用共享内存
    while(true)
    {
        int opt = 0;
        ssize_t s = read(fd,&opt,sizeof(int));//等待client通知。
        if(s==0)
        {
            cout<<"写端关闭"<<endl;
        }
        assert(s==4);
        cout<<str<<endl;;
    }
    shmdt(str);//去关联
    shmctl(shmid,IPC_RMID,nullptr);//删除共享内存
    close(fd);
    unlink(PATH_PIPE);
    return 0;
}

 comm.hpp

#include<iostream>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<cstdlib>
#include<unistd.h>
#include<assert.h>

#define PATH "/home/ds/vscode"
#define PROJID 0x1334
#define SIZE 4096 //建议为4k的整数倍

#define PATH_PIPE ".fifo"

 makefile

.PHONY:all
all:client server

client:client.cc
	g++ -o $@ $^ -std=c++11

server:server.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f client server

 

05、System V标准的三种进程通信

1、共享内存

对应操作:shmget、shmctl、shmat、shmdt

2、消息队列

对应操作:msgget、msgctl、msgsnd、msgrcv

3、信号量

对应操作:semget、semctl、semop(P操作)、semop(V操作)

4、查看和删除ipc资源

ipcs

ipcs -m/-q/-s

ipcrm -m/-q/-s

三种资源的数据结构:

 

 

三者共有的数据结构:

其中创建共享内存shmget中的key就在shmid_ds的ipc_perm中

操作系统通过数组方式将ipc资源管理起来

 使用时就强制类型转换:(struct shmid_ds*)array[0]。

6、mmap(待扩展)

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李逢溪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值