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

Linux进程间通信———共享内存

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

Linux进程间通信———共享内存

前两节我们讲的都是基于文件的通信方式(匿名管道和命名管道),今天我们将System V标准的进程间通信方式 在OS层面专门为进程间通信设计了一个方案,谁设计,xdm当然是计算机科学家和程序员(顶尖)。那么设计这个方案要不要给用户用,当然要给用户用,不然设计这个方案有什么意义。但是操作系统不相信任何用户,给用户提供功能的时候,采用系统调用! System V进程间通信,一定会存在专门同来通信的接口(System call)

进程间通信的本质是让不同的进程看到同一块资源。 System V的通信方式: 1.共享内存(Shared Memory) 2.消息队列(Message Queues) 3.信号量(Semaphore)

接下里xdm我们看一下共享内存实现的图解:

xdm看到没,现在进程A和进程B 中都有一块共享内存,可能在各个进程中的进程地址不同,但是通过页表可以拿到同一块物理内存,那么我们操作进程中的共享内存是不是就可以相当于操作物理内存了,是不是就可以通信了!!!!!!!! xdm我们可以理解为一下几个步骤: 1.通过某种调用,在内存中创建一份内存空间 2.通过某种调用,让进程“挂接”到这份新开辟的内存空间上 3.去关联(去挂接) 4.释放共享内存 xdm上面我们讲了共享内存的原理,接下来我们准备搞代码了。 准备工作: 1.操作系统存不存在多个进程,同时使用不同的共享内存进行通信呢?共享内存在系统中可能存不存在多份呢?有的话操作系统要不要管理这些共享内存呢?         答:如果不是我自己提的这个问题,我在心里肯定是问候提问者...。当然要操作系统来管理这些共享内存,不然不是乱套了吗? 怎么管理,记住六字真言:先描述,在组织!!!!!!!! 2.你怎么保证,两个或者多个进程,看到的是同一个共享内存呢?            答:先让进程看到同一个ID,共享内存一定要有一个唯一的标识符(ID),方便让不同的进程看到同一块共享内存资源。                 那么这个ID在哪里?一定在描述共享内存的数据结构体中。 这个ID是用户自己设定的!! 认识接口 创建共享内存:
#include 
#include 

       int shmget(key_t key, size_t size, int shmflg);
1,第一个参数key_t key是通过某种算法确定的一个key值,通信的进程要有相同的key,这个key 可以通过 ftok()得到
#include 
#include 

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

        pathname  路径
        proj_id   可以随便起
2,第二个参数是要设定的共享内存的大小,一半是4KB的整数倍,因为内存是以4KB为一页 3,第三个参数有一下几种选择 IPC_CREAT  //如果不存在就创建,如果存在就返回以这个key创建的共享内存的ID IPC_EXCL   //如果是和IPC_CREAT 一起使用的,如果存在就返回错误,不存在则成功 SHM_HUGETLB //一般不用 SHM_HUGE_2MB  // 一般不用 关联共享内存
#include 
#include 

       void *shmat(int shmid, const void *shmaddr, int shmflg);
1,第一个参数为创建共享内存的ID 2,第二个参数为让物理内存映射到进程地址空间的什么位置,一般我们填NULL. 3,第三个参数一般我们填0 xmd这个方法你们可以理解为malloc,你们就当成malloc使用就行了。 去关联共享内存
#include 
#include 

         int shmdt(const void *shmaddr);
这个方法是让进程共享空间和物理内存的共享内存失去联系 参数就当成free()用,上面我们不是申请了内存吗,下面就释放 就相当于         char * men = (char * ) malloc(64);         free(men) 一样使用。

释放共享内存
#include 
#include 

       int shmctl(int shmid, int cmd, struct shmid_ds *buf);
1,第一个参数是共享内存Id 2,第二个参数一般我们使用IPC_RMID------删除共享内存ID; 3,第三个参数我们不关心

好了xmd们我们现在就来搞代码了,定义一个sever.c client.c 让sever.c创建共享一个内存 common.h
#include
#include
#include
#include
#include
#include 
#define PATHNAME "./"
#define PROJ_ID 99
#define SIZE 4096
 server.c
#include "common.h"

int main()
{
	key_t key =  ftok(PATHNAME,PROJ_ID);  //生成key 
	if( key < 0)
	{
		perror("ftok()");
		exit(1);
	}

	int shmid = shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0644); //创建共享内存,通过key
	if(shmid < 0 )
	{
		perror("shmget()");
		exit(1);
	}
	printf("get share memory is sucesskey->%u :shmid->%dn",key, shmid);
	sleep(10);
	

	shmctl(shmid,IPC_RMID,NULL); //释放共享内存

	printf("lose share memory : %dn",shmid);
	sleep(10);

}
#include
#include
#include
#include
#include
#include 
#define PATHNAME "./"
#define PROJ_ID 99
#define SIZE 4096
XDM我们接下来看实验效果,我们make生成server可执行程序,我们另一个终端一直执行脚本命令查看共享内存资源如下图;

 运行: 得到共享内存

 释放共享内存 

在运行:

 XDM 你们有没有惊奇的看见共享内存的ID依次增大的,你们难道就没联想到什么数据结构吗?当然是数组,这个我会在后面详细讲解。这个ID其实就是数据下标。

 接下来,本节既然是讲进程间通信,那么我们就让进程通信起来。

XDM我们让client端向共享内存里写,server从共享内存中读,但是我们一运行,server就开始读了,并不会等client写了在读,可见共享内存的通信方式是异步而管道的通信方式是同步的。 XDM我们可以看到两个进程关联了共享内存,那么它的连接数就是2,它这个终端对齐可能有些问题,XDM要注意呀!! XDM看一下通信的代码吧, server.c
int main()
{
        key_t key =  ftok(PATHNAME,PROJ_ID);
        if( key < 0)
        {
                perror("ftok()");
                exit(1);
        }

        int shmid = shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0644);
        if(shmid < 0 )
        {
                perror("shmget()");
                exit(1);
        }
        printf("get share memory is sucesskey->%u :shmid->%dn",key, shmid);
        //sleep(10);
        //关联共享内存
        char * mem = (char*)shmat(shmid,NULL,0);

        //这里就是我们的通信逻辑了
                while(1)
                {
                        printf("%sn",mem);
                }

        //去关联共享内存
        shmdt(mem);

        shmctl(shmid,IPC_RMID,NULL);

        printf("lose share memory : %dn",shmid);
        sleep(10);

}
client.c
int main()
{
        key_t key =  ftok(PATHNAME,PROJ_ID);
        if( key < 0)
        {
                perror("ftok()");
                exit(1);
        }

        int shmid = shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0644);
        if(shmid < 0 )
        {
                perror("shmget()");
                exit(1);
        }
        printf("get share memory is sucesskey->%u :shmid->%dn",key, shmid);
        //sleep(10);
        //关联共享内存
        char * mem = (char*)shmat(shmid,NULL,0);

        //这里就是我们的通信逻辑了
                while(1)
                {
                        printf("%sn",mem);
                }

        //去关联共享内存
        shmdt(mem);

        shmctl(shmid,IPC_RMID,NULL);

        printf("lose share memory : %dn",shmid);
        sleep(10);

}
XDM讲到这里你们还要说进程间通信-----共享内存难的话,那只能重新做人了。。。 终结一下:就4步 1,创建共享内存ID 2,通过共享内存ID关联共享内存 3,去关联共享内存 4.释放共享内存 这些步骤接口记住就行,就下来我们讲的才是重点,是能够直接影响对怎个框架的了解。 我们通过命令man 2 shmctl看到如下代码
 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;    
               pid_t           shm_lpid;    
               shmatt_t        shm_nattch;  
               ...
           };

struct ipc_perm {
        key_t        key;                        调用shmget()时给出的关键字
        uid_t           uid;                      
        gid_t          gid;                       
        uid_t          cuid;                    
        gid_t         cgid;                   
        unsigned short   mode;    
        unsignedshort    seq;          
};
XDM们看到没,人家都直接说明了这是共享内存的数据结构 我们通过命令 man 2 msgctl看到如下代码
 struct semid_ds {
               struct ipc_perm sem_perm;  
               time_t          sem_otime; 
               time_t          sem_ctime; 
               unsigned long   sem_nsems; 
           };



  struct ipc_perm {
               key_t          __key; 
               uid_t          uid;   
               gid_t          gid;   
               uid_t          cuid;  
               gid_t          cgid;  
               unsigned short mode;  
               unsigned short __seq; 
           };
XDM们看到没,人家都直接说明了这是消息队列的数据结构  我们通过命令man 2 semctl看到如下代码
struct semid_ds {
               struct ipc_perm sem_perm;  
               time_t          sem_otime; 
               time_t          sem_ctime; 
               unsigned long   sem_nsems; 
           };



struct ipc_perm {
               key_t          __key; 
               uid_t          uid;   
               gid_t          gid;   
               uid_t          cuid;  
               gid_t          cgid;  
               unsigned short mode;  
               unsigned short __seq; 
           };
XDM看到没,所有的System V进程间通信的数据结构中,第一个成员是啥? 是struct ipc_perm,上面我不是设置了一个悬念吗?为什么进程间通信的msqid shmid semid是递增的,我说过它在内核中是用数组组织起来的,那又有人说,内核怎么组织呢,我们不是拿到一个表示唯一的资源(共享内存,消息队列,信号量),操作系统怎么将它们组织起来呢,很简单,我们不直接存储它的结构体指针,我们用数组将它的结构体中的第一个成员,用指针数组的方式保存起来,当我们要使用这些资源的时候,就拿出这个指针数组的成员,进行强转,类似(semid_ds*)&ipc_perm 这样就可以操作semid_ds中成员了,这样类似于c++中切片。

那么我们接下来看一看linux内核中进程间通信的源代码。

 ipc目录下,就是linux 内核进程间通信的源代码。包括共享内存(shm.c),消息队列(msg.c),信号量(sem.c).
#include 
#include 
#include 
#include  
#include 
#include 
#include 

extern int ipcperms (struct ipc_perm *ipcp, short semflg);
extern unsigned int get_swap_page(void);
static int findkey (key_t key);
static int newseg (key_t key, int shmflg, int size);
static int shm_map (struct shm_desc *shmd, int remap);
static void killseg (int id);

static int shm_tot = 0;  
static int shm_rss = 0; 
static int shm_swp = 0; 
static int max_shmid = 0; 
static struct wait_queue *shm_lock = NULL;
static struct shmid_ds *shm_segs[SHMMNI];

static unsigned short shm_seq = 0; 


static ulong swap_attempts = 0;
static ulong swap_successes = 0;
static ulong used_segs = 0;
xdm我现在就是不说你们也能猜出个大概了吧。 系统调用的接口就是对这些接口的封装
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/829985.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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