进程间通信之共享内存

进程间通信之共享内存

IPC对象

IPC对象这个概念需要理解,因为好多书或者料就直接说IPC就是共享内存、消息队列、信号灯集,其实IPC是一种机制,这种机制提供了进程间通信的通道,那么为什么加个System V呢,那是因为在System V 系统的四个版本中提出的进程通信的IPC这种机制。所以叫做System V IPC。

目前Linux也支持这三种机制:共享内存、消息队列、信号灯集

linux内核中定义了一个结构体:

struct ipc_perm
{
key_t key; 关键字
uid_t uid; /*共享内存所有者的有效用户ID */
gid_t gid; /* 共享内存所有者所属组的有效组ID*/ 
uid_t cuid; /* 共享内存创建 者的有效用户ID*/
gid_t cgid; /* 共享内存创建者所属组的有效组ID*/
unsigned short mode; /* Permissions + SHM_DEST和SHM_LOCKED标志*/
unsignedshort seq; /* 序列号*/
}; 

key比较关键,是识别这个共享通道的钥匙。
在这三种机制中都会用到这个创建的key;

一般用 ftok这个函数来创建钥匙。

key_t ftok( char * fname, int id )

例如:

if ((key = ftok(".", 's')) < 0)
    {
    perror("fail to ftok");
    exit(-1);
    }

这样就产生了一个key,其实也可以自己定义key,但是这样定义的key不安全。所以尽量用ftok来产生key

共享内存

共享内存,它是一种最为高效的进程间通信方式,进程可以直接读写内存,不需要任何数据的拷贝

为了在多个进程间交换信息,内核专门留出了一块内存区,可以有需要访问的进程将其映射到自己的私有地址空间,这种机制要
建立在绝对信任的基础上,否则,如果系统的一些重要信息放在这块内存区的话,可能会被利用。

进程不需要拷贝,那么句大大提高了效率,由于多个进程共享一段内存,所以也需要依靠某种同步机制,如互斥和信号量等。

函数

函数所需头文件
                                                #include <sys/types.h>
                                                #include <sys/ipc.h>
                                                #include <sys/shm.h>

共享内存的实现步骤:
##### 1. 创建/打开共享内存

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

函数参数:
- key:IPC_PRIVATE或ftok的返回值
- size:共享内存的大小
- shmflg:权限位

返回值:成功:共享内存段标识符
失败 -1;

2. 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

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

函数参数:
- shmid: 要映射的共享内存去标识符
- shmaddr:将共享内存映射到指定的地址(若为NULL,则表示由系统自动完成映射)
- shmflg:SHM_RDONLY 共享内存只读

默认为0:共享内存可读写

返回值: 成功,映射后的地址
失败 -1;

3. 撤销共享内存映射

int shmdt(const void * shmaddr);

函数参数:shmaddr:共享内存映射后的地址

函数返回值: 成功 0,失败 -1

4. 删除共享内存对象

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

函数参数:
- shmid:要操作的共享内存标识符

  • cmd: IPC_STAT(获取对象属性)

  • IPC_SET (设置对象属性)

  • IPC_RMID(删除对象)

  • buf:指定IPC_STAT/IPC_SET时用以保存/设置属性

    返回值;成功 0,出错 -1;

程序源码

/******************************* write写端 *****************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define N 64

typedef struct
{
    pid_t pid;
    char buf[N];
} SHM;

void handler(int signo)
{
}

int main()
{
    pid_t pid;
    key_t key;
    int shmid;
    SHM *shmadd;

if ((key = ftok(".", 's')) < 0)
    {
    perror("ftok error:");
    exit(-1);
    }

signal(SIGUSR1, handler);
    if ((shmid = shmget(key, sizeof(SHM), 0666|IPC_CREAT|IPC_EXCL)) < 0) // not first process
    {
    if (errno == EEXIST)
    {
    shmid = shmget(key, sizeof(SHM), 0666);
    shmadd = (SHM *)shmat(shmid, NULL, 0);
    pid = shmadd->pid;
    shmadd->pid = getpid();
    kill(pid, SIGUSR1);
    }
    else
    {
    perror("shmget error:");
    exit(-1);
    }
    }
    else // first process
    {
    shmadd = (SHM *)shmat(shmid, NULL, 0);
    shmadd->pid = getpid();
    pause();
    pid = shmadd->pid;
    }

while ( 1 )
    {
    printf("write: ");
    fgets(shmadd->buf, N, stdin);
    kill(pid, SIGUSR1);
    if (strncmp(shmadd->buf, "quit\n", 5) == 0) break;
    pause();
    }
    shmdt(shmadd);
    if (shmctl(shmid, IPC_RMID, NULL) < 0)
    {
    perror("shmctl error:");
    }

return 0;
}

/******************************** read读端 *****************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define N 64

typedef struct
{
    pid_t pid;
    char buf[N];
} SHM;

void handler(int signo)
{
}

int main()
{
    pid_t pid;
    key_t key;
    int shmid;
    SHM *shmadd;

if ((key = ftok(".", 's')) < 0)
    {
    perror("ftok error:");
    exit(-1);
    }

signal(SIGUSR1, handler);
    if ((shmid = shmget(key, sizeof(SHM), 0666|IPC_CREAT|IPC_EXCL)) < 0) // not first process
    {
    if (errno == EEXIST)
    {
    shmid = shmget(key, sizeof(SHM), 0666);
    shmadd = (SHM *)shmat(shmid, NULL, 0);
    pid = shmadd->pid;
    shmadd->pid = getpid();
    kill(pid, SIGUSR1);
    }
    else
    {
    perror("shmget error:");
    exit(-1);
    }
    }
    else // first process
    {
    shmadd = (SHM *)shmat(shmid, NULL, 0);
    shmadd->pid = getpid();
    pause();
    pid = shmadd->pid;
    }

while ( 1 )
    {
    pause();
    if (strncmp(shmadd->buf, "quit\n", 5) == 0) break;
    printf("read: ");
    printf("%s", shmadd->buf);
    kill(pid, SIGUSR1);
    }
    shmdt(shmadd);

return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值