第三季-第18课-共享内存通讯

第18课-共享内存通讯

 

18.1 基本概念

共享内存是IPC机制中的一种. 顾名思义,它允许两个不相关的进程访问同一段内存,这是传递数据的一种非常有效的方式。即,可以让进程A和B同时访问一段内存。

18.2 函数学习

1. 创建/获取共享内存

(1)函数名

shmget

(2)函数原型

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

(3)函数功能

创建或者获取共享内存,并返回其描述符。(allocates a shared memory segment)。

(4)所属头文件

#include<sys/ipc.h>

#include<sys/shm.h>

(5)返回值

成功:返回创建或者获取到的共享内存的描述符

失败:-1

(6)参数说明

key:共享内存的键值

size:共享内存的大小

shnflg:打开标志,如果使用了IPC_CREAT这个标志,就会新创建一个共享内存。

2. 映射共享内存

(1)函数名

shmat

(2)函数原型

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

(3)函数功能

把shmid指定的共享内存映射到进程的地址空间里。(shared memory operations)。

(4)所属头文件

#include<sys/types.h>

#include<sys/shm.h>

(5)返回值

成功:返回映射到进程空间之后的内存地址

失败:-1

(6)参数说明

shmid:要映射的共享内存的描述符

shmaddr:指定映射之后的地址,一般的情况下,改参数都是NULL,表明让linux系统自动的选择地址

shmflg:标志

3. 分离(脱离)共享内存

(1)函数名

shmdt

(2)函数原型

int shmdt(const void *shmaddr);

(3)函数功能

从进程地址空间中,断掉与共享内存的联系。(shared memory operations)。

(4)所属头文件

#include<sys/types.h>

#include<sys/shm.h>

(5)返回值

成功:0

失败:-1

(6)参数说明

shmaddr:要断开的共享内存的地址

4. 删除(控制)共享内存

(1)函数名

shmctl

(2)函数原型

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

(3)函数功能

控制共享内存(performs the control operation specified by cmd on the shared memory segment whose identifier is given in shmid)。

(4)所属头文件

#include<sys/ipc.h>

#include<sys/shm.h>

(5)返回值

成功:0

失败:-1

(6)参数说明

shmid:要控制的共享内存的id

cmd:决定执行什么样的控制操作,如IPC_RMID(表示删除)

内核为每一个共享存储段设置了一个shmid_ds结构,该结构如下:

struct shmid_ds        {

struct ipc_perm    shm_perm;   /*see Section 15.6.2*/

size_t            shm_segsz;   /*size of segment in bytes*/

pid_t             shm_lpid;    /*pid of last shmop*/

shmatt_t         shm_nattch;   /*number of current attaches*/

time_t           shm_atime;   /*last-attach time*/

time_t           shm_dtime;   /*last-detach time*/

time_t           shm_ctime;   /*last-change time*/

(按照支持共享存储段的需要,每种实现会在shmid_ds结构中增加其他成员)

buf:获取linux中描述共享内存的shmid_ds结构。基本不使用。

18.3 综合实例

1. 流程:

A和B两个进程,A先创建一个共享内存,然后再映射该共享内存。对于B进程先获取共享内存,然后再映射该共享内存。当用完了该共享内存后,A和B进程再分别分离该共享内存。A进程去删除共享内存。

2. 程序解读

我们设置两个进程,一个write进程,一个read进程。前一个进程是读取键盘上的输入的字符串,并且把字符串保存在共享内存之中。后一个进程的作用是,在共享内存中读取字符串,并且打印它们。

write进程的流程:(1)创建共享内存;(2)映射共享内存;(3)获取用户输入,把字符串放入共享内存,循环来做直到用户终止;(4)脱离共享内存。

write.c:

#include<sys/ipc.h>

#include<sys/shm.h>

#include<sys/types.h>

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#define TEXT_SZ 2048

struct shared_use_st

{

         int written_by_you;

         char some_text[TEXT_SZ];

};

int main()

{

         int running = 1;  //定义循环标志

         key_t key;

         key = ftok("/root",3);

         int shmid;

         struct shared_use_st *shared_stuff;

         char buffer[TEXT_SZ];    //fgets()函数用到的存储用的数组

         //1.创建共享内存;

         shmid = shmget(key, sizeof(struct shared_use_st),IPC_CREAT);

         if(shmid == -1)

         {

                  printf("creat share memory fail! ");

                  exit(EXIT_FAILURE);          //退出的标志

         }

         //2.映射共享内存.

         shared_stuff = (struct shared_use_st *)shmat(shmid, NULL, 0); //强制转换

         //3.循环

         while(running)

         {

                  //观看数据有没有被取走,没被取走一直等待

                  while(shared_stuff->written_by_you == 1)

                  {

                           sleep(1);

                           printf("wait read process! ");

                  }

                  //3.1 获取用户输入

                  fgets(buffer,TEXT_SZ,stdin);  //  char *fgets(char *s, int szie FILE *stream);

                  //3.2把字符串放入共享内存

                  strncpy(shared_stuff->some_text,buffer,TEXT_SZ);

                  shared_stuff->written_by_you = 1;

                  if(strncmp(buffer,"end",3)==0)

                  {

                           running = 0;             

                  }

         }

         //4.脱离共享内存

         shmdt((const void *)shared_stuff);   //强制转换

         return 1;

}

read进程流程:(1)创建/获取共享内存;(2)映射共享内存;(3)循环,打印共享内存中的字符串,直到收到结束的通知;(4)脱离共享内存;(5)删除共享内存。

read.c

#include<sys/ipc.h>

#include<sys/shm.h>

#include<sys/types.h>

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#define TEXT_SZ 2048

struct shared_use_st

{

         int written_by_you;

         char some_text[TEXT_SZ];

};

int main()

{

         int running = 1;  //定义循环标志

         int shmid;

         key_t key;

         key = ftok("/root",3);

         struct shared_use_st *shared_stuff;

         char buffer[TEXT_SZ]; 

         //1.创建/获取共享内存;

         shmid = shmget(key, sizeof(struct shared_use_st),IPC_CREAT);

         //2.映射共享内存;

         shared_stuff = (struct shared_use_st *)shmat(shmid, NULL, 0); //强制转换

         shared_stuff->written_by_you = 0;  //最初的标识是0;

         //3.循环

         while(running)

         {

                  //打印共享内存中的字符串,直到收到结束的通知;

                  if(shared_stuff->written_by_you == 1)

                  {

                           printf("write process is %s ",shared_stuff->some_text);

                           shared_stuff->written_by_you = 0;

                           if(strncmp(shared_stuff->some_text,"end",3)==0)

                                    running = 0;

                  }

         }

         //4.脱离共享内存;

         shmdt((const void *)shared_stuff);  //强制转换

         //5.删除共享内存。

         shmctl(shmid,IPC_RMID,0);

         return 1;

}

运行结果:在两个一样的终端中,先运行./read,在运行./write。我们在./write中输入的字符串会在./read中显示,直到输入end,两个程序都停止。

原文地址:https://www.cnblogs.com/free-1122/p/11352554.html