进程间通信之共享内存

来源:互联网 发布:chandler bing 知乎 编辑:程序博客网 时间:2024/06/16 05:12

进程间通信之共享内存

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 64typedef 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 64typedef 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;}
原创粉丝点击