System V IPC对象 共享内存、消息队列、信号灯集(6.7)
2015-06-08 20:22
531 查看
System V IPC对象 共享内存、消息队列、信号灯集
原理:
进程都是通过IPC对象唯一的名字,称为键key,找到IPC对象,但内核还是通过IPC对象的ID来找到它.
不同进程只要获得同一IPC对象的键key,就可以实现操作同一IPC对象,从而实际进程间通信
----------------------------------------------------------
key_t ftok(const char *pathname, int proj_id);
功能:获得key值
参数:
pathname 一个已经存在的文件路径,(避免传".")
proj_id 只会使用它的低八位
----------------------------------------------------------
例:
key_t key = ftok("/home/will/",'i');
一 共享内存
1.申请一块共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:申请一块指定大小共享内存
参数:
key
获得key方法:
a.IPC_PRIVATE : 在亲缘间进程通信使用
b.ftok()函数获得key :可用于非亲缘关系的进程间
size 申请的大小,(分配的实际大小是4K的倍数,但可用的大小为申请大小)
shmflg :
IPC_CREAT | 0666 对应的共享内存段不存在,则创建, 存在直接返回ID
IPC_CREAT | IPC_EXCL | 0666
如果对应的共享内存段已经存在,此时shmget调用失败,错误码设为EEXIST
返回值: 成功返回共享内存id;失败返回-1
注意:
当key值对应的共享内存ID不存在,此时会申请一块新的共享内存区域
当key值对应的共享内存ID存在,此时直接返回已经存在的共享内存ID
---------------------------------------------------------------
查看IPC对象
ipcs -m/-q/-s
删除IPC对象
ipcrm -m/-q/-s ID
-m:memory
-q:queue
-s:semaphore
练习:探测共享内存是否存在,如果存在,报错,如果不存在,则创建
2.共享内存映射
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存到进程的私有地址空间
参数:
shmid 共享内存段的标识
shmaddr NULL 让系统自动完成映射
shmflg 0 映射可以读写;
SHM_RDONLY 映射后只能读
返回值:
成功返回映射后的地址;失败返回 (void *)-1,并置errno
注意:进程结束,映射自动撤销
3.撤销共享内存映射
int shmdt(const void *shmaddr);
返回值:成功返回0;失败返回-1,并置errno
注意给shmdt传的地址必须是shmat获得的!
4.删除共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:对共享内存进行控制
若cmd参数设置为IPC_RMID,可实现删除共享内存
注意:删除共享内存并不是只要有进程删除就立刻删除,
而是当映射次数为0时才会真正删除。
例:删除共享内存
shmctl(shmid,IPC_RMID,NULL);
二 消息队列
1.创建消息队列
int msgget(key_t key, int msgflg);
功能:创建消息队列
参数:
key IPC_PRIVATE 或 ftok()
msgflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL | 0666
返回值:
成功返回ID,失败返回-1
2.发送消息
//封装消息结构体
typedef struct
{
//第一个字段必须是消息类型
long type;
//正文部分
...
}msg_t;
//消息正文大小
#define MSG_LEN (sizeof(msg_t) - sizeof(long))
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列中添加消息
参数:
msqid 消息队列的ID
msgp 消息存放的地址
msgsz 消息正文的大小--- sizeof(msg_t) - sizeof(long)
msgflg
0:阻塞的方式发送消息
IPC_NOWAIT:非阻塞发送消息(当消息队列中没有可用空间时,不阻塞,立即返回一个错误码EAGAIN)
返回值:
成功返回0,失败返回-1
例如:发送消息类型是100,消息内容"hello world"
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:接收指定类型的消息
参数:
msgid 消息队列ID
msgp 接收的消息存放的地址
msgsz 消息正文的大小
msgtyp 接收的消息的类型
msgflg 0(阻塞方式调用) 或 IPC_NOWAIT (没有指定类型消息,不阻塞,立即返回)
返回值:
成功返回接收正文的大小,失败返回-1
例如:接收消息类型为100的消息
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:对消息队列进行控制
若cmd参数设置为IPC_RMID,可实现立即删除消息队列
例:msgctl(msqid,IPC_RMID,NULL);
练习:通过消息队列让A终端上父子进程和B终端上子父进程聊天
要求一边输入quit,所有进程结束.
三 信号灯集
(1)创建一个信号灯集
int semget(key_t key, int nsems, int semflg);
功能:创建或获得信号灯集
参数:
key IPC_PRIVATE 或 ftok()
nsems 信号灯集中信号灯的个数(注意:信号灯的编号从0开始)
semflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL | 0666
返回值:
成功返回id,失败返回-1
(2)初始化信号灯集中的信号灯的值
int semctl(int semid, int semnum, int cmd, .../*union semun arg*/);
功能:对信号灯集中信号灯进行控制
参数:
semid :信号灯集ID
semnum :操作的信号灯编号,注意信号灯集中的信号灯编号从0开始
cmd :控制命令 SETVAL:设置信号灯值 GETVAL:获得信号灯值 都需第四个共用体类型参数
IPC_RMID:立即删除信号灯集
arg :cmd参数中若指定SETVAL需要保存要设置的信号灯值,或GETVAL
例如:初始化信号灯集中0号信号灯的值为1
原理:
进程都是通过IPC对象唯一的名字,称为键key,找到IPC对象,但内核还是通过IPC对象的ID来找到它.
不同进程只要获得同一IPC对象的键key,就可以实现操作同一IPC对象,从而实际进程间通信
----------------------------------------------------------
key_t ftok(const char *pathname, int proj_id);
功能:获得key值
参数:
pathname 一个已经存在的文件路径,(避免传".")
proj_id 只会使用它的低八位
----------------------------------------------------------
例:
key_t key = ftok("/home/will/",'i');
一 共享内存
1.申请一块共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:申请一块指定大小共享内存
参数:
key
获得key方法:
a.IPC_PRIVATE : 在亲缘间进程通信使用
b.ftok()函数获得key :可用于非亲缘关系的进程间
size 申请的大小,(分配的实际大小是4K的倍数,但可用的大小为申请大小)
shmflg :
IPC_CREAT | 0666 对应的共享内存段不存在,则创建, 存在直接返回ID
IPC_CREAT | IPC_EXCL | 0666
如果对应的共享内存段已经存在,此时shmget调用失败,错误码设为EEXIST
返回值: 成功返回共享内存id;失败返回-1
注意:
当key值对应的共享内存ID不存在,此时会申请一块新的共享内存区域
当key值对应的共享内存ID存在,此时直接返回已经存在的共享内存ID
---------------------------------------------------------------
查看IPC对象
ipcs -m/-q/-s
删除IPC对象
ipcrm -m/-q/-s ID
-m:memory
-q:queue
-s:semaphore
练习:探测共享内存是否存在,如果存在,报错,如果不存在,则创建
2.共享内存映射
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存到进程的私有地址空间
参数:
shmid 共享内存段的标识
shmaddr NULL 让系统自动完成映射
shmflg 0 映射可以读写;
SHM_RDONLY 映射后只能读
返回值:
成功返回映射后的地址;失败返回 (void *)-1,并置errno
注意:进程结束,映射自动撤销
3.撤销共享内存映射
int shmdt(const void *shmaddr);
返回值:成功返回0;失败返回-1,并置errno
注意给shmdt传的地址必须是shmat获得的!
4.删除共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:对共享内存进行控制
若cmd参数设置为IPC_RMID,可实现删除共享内存
注意:删除共享内存并不是只要有进程删除就立刻删除,
而是当映射次数为0时才会真正删除。
例:删除共享内存
shmctl(shmid,IPC_RMID,NULL);
二 消息队列
1.创建消息队列
int msgget(key_t key, int msgflg);
功能:创建消息队列
参数:
key IPC_PRIVATE 或 ftok()
msgflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL | 0666
返回值:
成功返回ID,失败返回-1
2.发送消息
//封装消息结构体
typedef struct
{
//第一个字段必须是消息类型
long type;
//正文部分
...
}msg_t;
//消息正文大小
#define MSG_LEN (sizeof(msg_t) - sizeof(long))
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列中添加消息
参数:
msqid 消息队列的ID
msgp 消息存放的地址
msgsz 消息正文的大小--- sizeof(msg_t) - sizeof(long)
msgflg
0:阻塞的方式发送消息
IPC_NOWAIT:非阻塞发送消息(当消息队列中没有可用空间时,不阻塞,立即返回一个错误码EAGAIN)
返回值:
成功返回0,失败返回-1
例如:发送消息类型是100,消息内容"hello world"
typedef struct { long type; char buf[1024]; #if 0/*{{{*/ time_t t; pid_t pid; #endif/*}}}*/ }msg_t; msg_t msg; msg_t *pmsg = (msg_t *)malloc(sizeof(msg_t)); msg.type = 100; strcpy(msg.buf,"hello world"); sprintf(msg.buf,"hello world"); if(msgsnd(msgid,&msg,MSG_LEN,0) < 0) { .... }3.接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:接收指定类型的消息
参数:
msgid 消息队列ID
msgp 接收的消息存放的地址
msgsz 消息正文的大小
msgtyp 接收的消息的类型
msgflg 0(阻塞方式调用) 或 IPC_NOWAIT (没有指定类型消息,不阻塞,立即返回)
返回值:
成功返回接收正文的大小,失败返回-1
例如:接收消息类型为100的消息
msg_t msg; if(msgrcv(msgid,&msg,MSG_LEN,100,0) < 0) { ..... } printf("------------------------------\n"); printf("TYPE : %ld.\n",msg.type); printf("MTXT : %s.\n",msg.buf); printf("------------------------------\n");4.删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:对消息队列进行控制
若cmd参数设置为IPC_RMID,可实现立即删除消息队列
例:msgctl(msqid,IPC_RMID,NULL);
练习:通过消息队列让A终端上父子进程和B终端上子父进程聊天
要求一边输入quit,所有进程结束.
三 信号灯集
(1)创建一个信号灯集
int semget(key_t key, int nsems, int semflg);
功能:创建或获得信号灯集
参数:
key IPC_PRIVATE 或 ftok()
nsems 信号灯集中信号灯的个数(注意:信号灯的编号从0开始)
semflg IPC_CREAT | 0666 或 IPC_CREAT | IPC_EXCL | 0666
返回值:
成功返回id,失败返回-1
(2)初始化信号灯集中的信号灯的值
int semctl(int semid, int semnum, int cmd, .../*union semun arg*/);
功能:对信号灯集中信号灯进行控制
参数:
semid :信号灯集ID
semnum :操作的信号灯编号,注意信号灯集中的信号灯编号从0开始
cmd :控制命令 SETVAL:设置信号灯值 GETVAL:获得信号灯值 都需第四个共用体类型参数
IPC_RMID:立即删除信号灯集
arg :cmd参数中若指定SETVAL需要保存要设置的信号灯值,或GETVAL
例如:初始化信号灯集中0号信号灯的值为1
union semun { int val; /* Value for SETVAL */ struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ unsigned short *array; /* Array for GETALL, SETALL */ struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */ }; union semun sem_val; sem_val.val = 1; if(semctl(semid,0,SETVAL,sem_val) < 0) { ... }(3)封装p/v操作
int semop(int semid, struct sembuf *sops, unsigned nsops); //参数: semid 信号灯集id sops struct sembuf //其中部分成员 { //操作信号灯集中信号灯序号 unsigned short sem_num; /* semaphore number */ //sem_op -1:p操作 1:v操作 0:等待 short sem_op; /* semaphore operation */ //0:阻塞 IPC_NOWAIT:非阻塞 SEM_UNDO:进程结束的时候若未释放共享资源,由内核释放申请的资源 short sem_flg; /* operation flags */ } nsops 操作的信号灯个数 //->p操作: // 信号灯集的id 操作具体的信号灯编号(从0开始) void P(int semid, int s_num) { struct sembuf sem; sem.sem_num = s_num; sem.sem_op = -1; /*sem.sem_flg = 0;*/ sem.sem_flg = SEM_UNDO; if(semop(semid,&sem,1) < 0) { perror("fail to semop"); exit(EXIT_FAILURE); } return; } //->v操作: // 操作信号灯集中信号灯序号 void V(int semid,int s_num) { struct sembuf sem; sem.sem_num = s_num; sem.sem_op = 1; sem.sem_flg = SEM_UNDO; if(semop(semid,&sem,1) < 0) { perror("fail to semop"); exit(EXIT_FAILURE); } return; }(4)删除信号灯集
int semctl(int semid, int semnum, int cmd, ...); //如果cmd是IPC_RMID,不需要第四个参数 if(semctl(semid,0,IPC_RMID) < 0) { perror("fail to semctl"); exit(exit_failure); }
相关文章推荐
- 浅析final finally finalize
- amanda安装
- 【Math类】常用函数
- lua demo
- Android中Toast不显示的解决方案
- 运动目标检测、阴影检测及目标跟踪中用得到的标准测试视频下载(大量IBM提供视频)
- jdk6,jdk7直链下载方法
- 监视器 RUIGE瑞鸽高清监视器TL-S1700HD
- listview
- vc 改变控制台字符颜色
- 【转载】Git 常用命令整理
- postfix和dovecot的邮件认证及加密
- NFS(网络文件系统)简述及使用
- 多层感知机(Multilayer Perceptron)
- Linux 设备模型之(总线、设备和驱动程序)(三)
- gpio_direction_output 和 gpio_set_value用法的区别
- 小数化成最简式分数
- 【架构】关于RabbitMQ
- spring整合消息队列rabbitmq
- RabbitMQ消息队列(九):Publisher的消息确认机制