当前位置: 首页 > news >正文

winxp下做网站nba球队排名

winxp下做网站,nba球队排名,网站建设找单,最大的建筑招工平台 app目录 写在前面的话 System V共享内存原理 System V共享内存的建立 代码实现System V共享内存 创建共享内存shmget() ftok() 删除共享内存shmctl() 挂接共享内存shmat() 取消挂接共享内存shmdt() 整体通信流程的实现 写在前面的话 上一章我们讲了进程间通信的第一种方式…

目录

 写在前面的话

System V共享内存原理

System V共享内存的建立

代码实现System V共享内存

创建共享内存shmget()

ftok()

删除共享内存shmctl()

挂接共享内存shmat()

取消挂接共享内存shmdt()

整体通信流程的实现


 写在前面的话

         上一章我们讲了进程间通信的第一种方式 --- 管道,这一章我们将继续讲解进程间的通信的第二种方式 --- system V共享内存

        在讲解之前,还是先建议去把进程间通信管道的方式和原理搞明白,这样理解起system V共享内存来会简单许多。

System V共享内存原理

        共享内存是一种进程间通信(IPC)的机制,允许多个进程共享同一块内存区域,以便它们可以直接读取和写入其中的数据,从而实现高效的数据共享和通信。

         在共享内存中,当进程task_struct创建或连接到共享内存段时,操作系统会为每个进程分配一个虚拟地址空间mm_srtuct,将这个虚拟地址通过页表 映射到相同的物理内存区域。这样,多个进程就可以通过自己的虚拟地址访问相同的物理内存,实现对同一块内存的共享访问。通过虚拟地址到物理地址的映射,多个进程可以看到同一个共享内存.

        那么如何释放共享内存呢?

也很简单,只需要将每个进程 和 共享内存建立的映射去掉,然后释放掉共享内存即可.

System V共享内存的建立

        假设有很多进程都在用共享内存,这样内存中也会出现大量的 共享内存块,所以OS要把这些共享内存块管理起来,方式:先描述再组织,这样要把共享内存属性抽象成数据结构,然后利用一些方式将这些数据结构组织起来.所以:

       1. 共享内存 = 共享内存块 + 共享内存块对应的内核数据结构

       2.共享内存块一定不属于任何一个进程,而是属于操作系统.

建立共享内存的大体流程如下:

  1. 创建共享内存段:使用 shmget() 系统调用来请求创建一个共享内存段。该调用需要指定共享内存的大小、权限和标志等参数,并返回一个唯一的共享内存标识符。

  2. 连接到共享内存段:使用 shmat() 系统调用将当前进程附加到共享内存段。这个调用将返回共享内存段的地址,并将该地址映射到当前进程的虚拟地址空间。

  3. 访问共享内存:连接到共享内存的进程可以通过在其地址上执行内存操作,直接读取和写入共享内存段中的数据。进程可以使用指针、数组或结构体等方式在共享内存段中存储和访问数据。

  4. 分离共享内存:当进程完成对共享内存的访问后,使用 shmdt() 系统调用将其与共享内存段分离。分离后,进程将无法再访问共享内存段,但共享内存段仍然存在。

  5. 删除共享内存段:当不再需要共享内存段时,可以使用 shmctl() 系统调用删除它。这个调用需要指定共享内存标识符和特定的控制操作,比如传递 IPC_RMID 参数表示删除共享内存段.

        具体的使用方法及原理,我们在下面马上讲解。

代码实现System V共享内存

        按我们上面所说的,第一步是利用shmget()建立共享内存段,我们来看一下它的用法.

创建共享内存shmget()

        这个函数作用是创建并获取一个共享内存。

        先说第二个参数,是size,代表的是要创建的共享内存有多大

        再来说第三个参数shmflg,代表我们要设置的选项,共有两个选项:

        1.IPC_CREATE:创建共享内存,如果底层已经存在,则获取并返回;如果不存在,则创建共享内存然后再返回,

        2.IPC_EXCL:单独使用它没有意义,一般和IPC_CREATE合起来使用,见下:

        3.IPC_CREATE | IPC_EXCL:如果底层不存在,则创建共享内存并返回;如果底层存在,则出错返回。言外之意,如果返回成功,那么一定是一个全新的内存块

        最后再来说第一个参数 key.

        我们利用共享内存通信时会有一个问题,要通信的对方进程,怎么保证对方看到的共享内存就是我创建的呢?毕竟有很多共享内存.

        这个我们就需要通过key,key数据是多少不重要,只要保证在系统里唯一即可! 两个通信端A 和 B,只要使用同一个key,便可以找到同一块共享内存。因为key是唯一的,即这个共享内存块也是唯一的!

        相当于是给每个共享内存块编了个号,这个号码是唯一的,所以只要拿到了编号,就能找到相同的共享内存块。

        那么这个唯一的key值如何得到呢?这里需要用到ftok()函数

ftok()

我们先来看一下函数的使用:

  1. pathname:一个字符串,用于标识一个文件的路径名。通常会选择一个已经存在的文件,因为 ftok() 函数将使用该文件的inode编号和 proj_id 参数通过算法来生成键值key。

  2. proj_id:一个整数,作为用于生成键的项目标识号。该参数通常取一个非负整数。


然后我们来看一下返回值:

         看到如果成功的话,生成的键值被返回,否则-1被返回。

这些说清楚了,我们来用一下吧:

首先四个文件,comm.hpp,里面包含了必要的头文件及宏定义,这个便不再展示了;

        Log.hpp是日志文件,上一章我们写了,这里不写也可以,直接cout输出也行。

        shmClient.cc中我们写入以下代码:

#include "comm.hpp"
#include "Log.hpp"
int main()
{key_t k = ftok(PATH_NAME,PROJ_ID);Log("create key done",Debug) << " client key : " << k << endl;return 0;
}

        shmServer中拷贝一份代码,然后把输出语句中的client改成server,然后我们编译运行来及看一下效果:

         可以发现生成了一样的key值,这样便可以找到同一块共享内存块了.


这样shmget的第一个参数也讲完了,接下来说一下返回值.

    返回值是如果建立成功,则返回这段共享内存的标识符,否则返回-1并且错误码被设置。

删除共享内存shmctl()

        当我们创建好共享内存后,最后还需要删除它,因为共享内存的生命周期是随内核的!

        不关闭的话,只要操作系统一直在运行,那么它就一直存在,占用空间资源。所以必须需要删除.

        有两种方法删除:手动指令删除、代码删除

指令删除:

        我们首先创建了一个共享内存,然后该进程执行完毕,进程退出。                

         我们在终端输入

ipcs -m

        来查看当前共享内存的使用情况

         可以发现确实没有释放掉。然后我们可以利用

ipcrm -m shmid

        来删除对应的共享内存,此时我输入这条指令后便没有了这块内存了。

这里提到了perms,这个是权限的意思,我们可以在shmget的第三个选项 加上权限,如下:

    int shmid = shmget(k,SHM_SIZE,IPC_CREAT | IPC_EXCL | 0666);

此时perms就变成了666. 

代码删除

        每次手动删除太麻烦了,我们直接卸载程序里到时候自动帮我们删除不更方便吗

        所以我们需要用到一个函数shmctl()

 

  1. shmid:共享内存段的标识符(ID),即通过调用 shmget() 函数创建共享内存时返回的 shmid

  2. cmd:控制命令,用于指定要执行的操作类型。可以使用以下命令之一:

    • IPC_STAT:获取共享内存段的状态信息,将结果存储在 buf 参数指向的 struct shmid_ds 结构体中。
    • IPC_SET:设置共享内存段的状态信息,使用 buf 参数中提供的值。
    • IPC_RMID删除共享内存段,将其标记为删除状态,并在释放最后一个进程的附加段之后销毁。
  3. buf:一个指向 struct shmid_ds 结构体的指针,用于传递或接收共享内存段的状态信息。

     这是struct shmid_ds结构体指针的内容:

struct shmid_ds {struct ipc_perm shm_perm;   // 共享内存的权限信息size_t shm_segsz;           // 共享内存的大小time_t shm_atime;           // 上一次连接共享内存的时间time_t shm_dtime;           // 上一次与共享内存断开连接的时间time_t shm_ctime;           // 上一次修改共享内存的时间pid_t shm_cpid;             // 创建共享内存的进程IDpid_t shm_lpid;             // 最后一个操作共享内存的进程IDunsigned short shm_nattch;  // 当前连接到共享内存的进程数量// 其他字段...
};

其中第二个参数cmd我们目前只使用第3个IPC_RMID删除共享内存的选项。

第三个参数buf我们暂且不使用,直接传入nullptr。

    int n = shmctl(shmid,IPC_RMID,nullptr);

挂接共享内存shmat()

        我们创建好了共享内存,当然需要将进程的地址空间与其挂接上,然后 才能使用,这里使用到了函数shmat().

 

shmat() 函数接受三个参数:

  1. shmid:共享内存段的标识符(ID),即通过调用 shmget() 函数创建共享内存时返回的 shmid。表示你想挂接哪一个共享内存。

  2. shmaddr:共享内存段连接到进程地址空间的首地址。通常将其设置为 NULL,指示系统选择适当的地址。如果想要指定特定的地址,可以传递一个非空的地址值。但不建议这样使用。

  3. shmflg:标志参数,用于指定连接共享内存的选项。常用的选项有:

    • SHM_RDONLY:以只读方式连接共享内存,不允许写入。
    • SHM_RND:将 shmaddr 参数忽略,系统选择一个地址以进行连接。

              其他选项参考 shmat() 函数的文档以获得更多详细信息。


        它的返回值是void*,是一个指向共享内存段的指针,即连接到进程地址空间的首地址。我们需要将结果强转为我们需要的类型,一般为char*,和malloc的使用类似。

所以可以如下这样使用:

    char* shmaddr = (char*)shmat(shmid,nullptr,SHM_RDONLY);

shmaddr便是连接的进程地址空间的首地址。

取消挂接共享内存shmdt()

        删除共享内存时,无论有多少个进程与共享内存连接,都会被直接清理掉,这种方式不太好,所以在删除共享内存前,可以先取消挂接。当挂接数为0时,再释放共享内存。

        同样先来看一下用法:

         这个参数正好是我们刚才shmat返回的进程地址空间的首地址shmaddr,表示将共享内存从调用进程的地址空间中分离,使得该进程无法再访问该共享内存

        再来看一下返回值:

        如果取消挂接成功,则返回0,失败则返回-1.

所以我们可以直接这么使用:

    //3.将指定的共享内存,挂接到自己的地址空间char* shmaddr = (char*)shmat(shmid,nullptr,SHM_RDONLY);//这里就是通信的逻辑//4.将指定的共享内存,从自己的进程地址空间取消关联int n = shmdt(shmaddr);assert(n != -1);

整体通信流程的实现

        认识了上面的接口,加上我们在共享内存的建立中所说的步骤,我们便可以制作一个完整的利用System V共享内存通信的流程了。        

        0. 我们要利用ftok()生成共享内存唯一标识key.

        1. 然后我们利用key调用shmget()函数创建共享内存

        2. 接着我们需要利用shmat()挂接上共享内存

        3. 然后实现通信的流程

        4. 利用shmdt()取消挂接

        5. 利用shmctl()删除共享内存(一般是server,谁创建的谁删除)

这里一共四个文件,分别为Log.hpp(日志信息),comm.hpp(共用的头文件),shmServer.cc, shmClient.cc 

Log.hpp(日志信息)

#pragma once
#include <iostream>
#include <ctime>
#include<string>
using namespace std;#define Debug 0
#define Notice 1
#define Warning 2
#define Error 3string msg[] = {"Debug ","Notice","Warning","Error"
};ostream& Log(string message,int level)
{cout << " | " << (unsigned)time(NULL) << " | " << msg[level] << " | " << message;return cout;
}

comm.hpp(共用的头文件)

#pragma once 
#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
using namespace std;#define PATH_NAME "/home/hyx"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //最好是页(PAGE:4096)的整数倍,假设是4097,OS也会申请4096*2的空间,剩下的4095空间相当于浪费了 

shmServer.cc

#include "comm.hpp"
#include "Log.hpp"
string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof(buffer),"0x%x",k);return buffer;
}
int main()
{//1.创建公共的key值key_t k = ftok(PATH_NAME,PROJ_ID);Log("create key done",Debug) << " server key : " << TransToHex(k) << endl;//2.创建共享内存 --- 建议创建一个全新的共享内存 int shmid = shmget(k,SHM_SIZE,IPC_CREAT | IPC_EXCL | 0666);if(shmid == -1){perror("shmget");exit(1);}Log("create shm done",Debug) << " shmid: " << shmid << endl;// sleep(10);//3.将指定的共享内存,挂接到自己的地址空间char* shmaddr = (char*)shmat(shmid,nullptr,SHM_RDONLY);Log("attach shm done",Debug) << " shmid: " << shmid << endl;// sleep(10);//这里就是通信的逻辑//将共享内存当做一个大字符串// char buffer[SHM_SIZE];//结论1:只要双方使用shm,一方直接向共享内存中写入数据。另一方就可以立马看到//       共享内存是所有进程IPC,速度最快的! 因为不需要过多的拷贝!表现为不需要将数据拷贝给操作系统for(;;){printf("%s\n",shmaddr);if(strcmp(shmaddr,"quit") == 0) break;sleep(1);}//4.将指定的共享内存,从自己的进程地址空间取消关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm done",Debug) << " shmid: " << shmid << endl;// sleep(10);//5..删除共享内存n = shmctl(shmid,IPC_RMID,nullptr);assert(n != -1);Log("delete shm done",Debug) << " shmid: " << shmid << endl;return 0;
}

shmClient.cc 

#include "comm.hpp"
#include "Log.hpp"
int main()
{key_t k = ftok(PATH_NAME,PROJ_ID);if(k < 0){Log("create key done", Error) << "client key : " << k << endl;exit(1);}Log("create key done",Debug) << " client key : " << k << endl;//获取共享内存int shmid = shmget(k,SHM_SIZE,IPC_CREAT);if(shmid < 0){Log("create shm failed", Error) << "client key : " << k << endl;exit(2);}Log("create shm success", Debug) << "client key : " << k << endl;// sleep(10);char* shmaddr = (char*)shmat(shmid,nullptr,0);if(shmaddr == nullptr){Log("attach shm failed", Error) << "client key : " << k << endl;exit(3);}Log("attach shm success", Debug) << "client key : " << k << endl;// sleep(10);//使用//client将共享内存看做一个char类型的bufferchar a = 'a';for(;a <= 'e'; a++){//我们是每一次都向shmaddr[共享内存起始地址]写入snprintf(shmaddr,SHM_SIZE-1,\"hello,server, my pid is: %d, inc : %c\n",getpid(),a);sleep(2);}strcpy(shmaddr,"quit");//去关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm success",Debug) << "client key : " << k << endl;// sleep(10);//client 不需要删除共享内存,server负责这些,和client没关系。return 0;
}

然后我们编译运行,分两个窗口观察:

 client

 可以看到,双方都实现了通信。

到这里System V共享内存就介绍完毕了,如果有不懂或疑问的地方,欢迎评论区或私信哦~

http://www.ds6.com.cn/news/99339.html

相关文章:

  • 开发软件和做网站的区别北京优化靠谱的公司
  • 卡通风格网站欣赏郑州网络优化实力乐云seo
  • 做网站域名起什么作用上海seo优化外包公司
  • 乐清网站只做百度知道合伙人
  • 公司免费网站搭建湖南seo推广软件
  • 网站配置文件在哪里天津百度
  • 微信小程序商城官网杭州网站seo外包
  • workerman 做网站廊坊快速优化排名
  • 网站定制业务营销网站建设免费
  • 四川省建设工程招投标网站整合营销
  • 怎么用VS2012建设网站外链网站是什么
  • com网站域名百度竞价排名什么意思
  • 英雄联盟网站模版网络推广推广
  • 自助商城网站建设seo关键词快速排名软件
  • 创建wordpress主题南阳seo优化
  • 做网站需要什么配置服务器推广效果最好的平台
  • 做网站怎么切片网站建设
  • 人才网站 建设好 窗口百度公司排名
  • 做网站一定要买主机吗长沙网站seo方法
  • wordpress rest api评论seo的主要内容
  • 做新得网站可以换到原来得域名嘛百度seo公司兴田德润
  • wordpress iis 伪静态seo网站优化方
  • sae 企业网站职业培训网
  • 网站建设合同注意事项网站运营seo实训总结
  • 北京做微信网站足球世界排名
  • 网站设计与制治疗腰椎间盘突出的特效药
  • 哪个网站可以学做馒头网站如何被百度快速收录
  • 网站建设入门怎么推广自己的微信号
  • 南昌建设公司网站网站外包公司有哪些
  • 惠州百度推广排名优化网站专业术语中seo意思是