进程间通信:共享内存

10 篇文章 2 订阅

系统V的IPC通信机制包括了消息队列、共享内存和信号量。每一种IPC结构结构都有一个非负整数标志,当创建一个IPC结构时,调用进程都必须提供一个类型为key_t的键(key)。操作系统把这个键转换为一个IPC的唯一标识符。

可以使用以下方式来指定一个键,调用函数如下:

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char* path, int projectid);

创建好以后就可以使用这个键去创建一个新的IPC结构了。服务器只需要调用合适的get函数去创建就好了。这里我们主要谈论共享内存。

一. 共享内存

顾名思义,通过共享一块内存空间,其他进程不需要进行读取操作就可以看到一份公共资源,从而进行相互交换信息,但是共享内存之中不提供同步与互斥机制,这就需要我们用户自己去设计,简单的就是执行PV操作了。

要使用一个共享内存段,进程就必须获得该共享内存段的标志符,这里可以使用shmget函数,源码如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

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

参数size指定了共享内存段的大小,建议制定为页的整数倍,参数key制定了该共享内存段使用的key,可以使用ftok得到,参数shmflg可以设置为IPC_CREAT和IPC_EXCL,两个同时设置代表
如果共享内存段不存在则创建,如果存在则返回一个标识符,只使用IPC_CREAT时代表共享内存段存在则打开,不存在则返回-1,同时将失败原因保存在errno中。

创建了一个共享内存段后就要对他进行一系列的操作,比如,删除。这里就要使用shmctl函数:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

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

参数shmid包括了共享内存段的标识符,参数buf指向一个类型为struct_ds的结构体,定义了内存段的性质:

struct shmid_ds {
    struct ipc_perm     shm_perm;   /* operation perms */
    int         shm_segsz;  /* size of segment (bytes) */
    __kernel_time_t     shm_atime;  /* last attach time */
    __kernel_time_t     shm_dtime;  /* last detach time */
    __kernel_time_t     shm_ctime;  /* last change time */
    __kernel_ipc_pid_t  shm_cpid;   /* pid of creator */
    __kernel_ipc_pid_t  shm_lpid;   /* pid of last operator */
    unsigned short      shm_nattch; /* no. of current attaches */
    unsigned short      shm_unused; /* compatibility */
    void            *shm_unused2;   /* ditto - used by DIPC */
    void            *shm_unused3;   /* unused */
};

参数cmd可以设置为IPC_RMID,表示从系统中删除shmid指定共享内存段的标识符,并删除相应的数据结构。

如果一个进程要使用一个共享内存段,他必须连接该内存段,也就是说必须将内存段映射到进程的地址空间。可以使用shmat函数:

#include <sys/types.h>
#include <sys/ipc.h>
#include <shm.h>

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

参数shmid指定了要连接的共享内存段的标识符;

参数shmaddr指定了共享内存的地址,一般设置为0,表示由系统选择,因为系统是最了解地址的;

参数shmflg包括了常量SHM_RDONLY,那么内存段就是只读的,否则就是读写的,如果成功连接,返回开始地址,否则返回(void*)-1,同时将失败原因保存在errno中。

在使用完共享内存段以后,进程可以使用shmdt来断开连接;

#include <sys/types.h>
#include <sys/ipc.h>
#include <shm.h>

void *shmdt(void* shmaddr);

参数是shmat的返回值。

二.共享内存代码
//头文件comm.h
#ifndef _COMM_H_
#define _COMM_H_

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define PATHNAME "."
#define PROJ_ID 0x6666

int creatShm(int size);   //共享内存的创建
int destroyShm(int shmid);//共享内存的销毁
int getShm(int size);  //共享内存获取


#endif //_COMM_H_H
//comm.c
#include "comm.h"

static int commShm(int size,int flags)
{
    key_t key = ftok(PATHNAME, PROJ_ID);  //key值获取
    if(key<0){
        perror("ftok");
        return -1;
    }
    int shmid = shmget(key, size, flags); //创建共享内存
    if(shmid<0){
        perror("shmget");
        return -2;
    }
    return shmid;
}
int creatShm(int size)
{
    return commShm(size, IPC_CREAT|IPC_EXCL|0666);
}
int destroyShm(int shmid)
{
    if(shmctl(shmid, IPC_RMID, 0)<0){   //共享内存销毁
        perror("shmctl");
        return -2;
    }
    return 0;
}
int getShm(int size)
{
    return commShm(size,IPC_CREAT);

}
///server.c
#include "comm.h"
int main()
{
    int shmid = creatShm(4096);   //创建
    sleep(4);
    char * addr = (char*)shmat(shmid, NULL, 0); //连接内存段
    sleep(3);
    while(1){
        printf("%s\n", addr);
        sleep(1);
    }
    shmdt(addr);         //断开连接
    destroyShm(shmid);  //销毁共享内存
    return 0;
}
#include "comm.h"


int main()
{
    int shmid = getShm(4096);   //打开共享内存
    sleep(4);
    char * addr = (char*)shmat(shmid, NULL, 0); //连接

    sleep(3);
    int i = 0;
    while(1){   //在内存中写入数据
        addr[i] = 'A' + i;   
        i++;
        addr[i] = 0;
        sleep(1);
    }
    shmdt(addr); //断开连接
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值