消息队列
概述
$消息队列是消息的链接表,包括Posix 消息队列systemV 消息队列。系统V消息队列是随内核持续的,只有在内核重起或人工删除时,该消息队列才会被删除。目前被大量使
用。
$用户可以从消息队列中添加和读取消息。具有一定的FIFO特性,但可以实现消息的随机查询
$这些消息存在于内核中,由“队列ID”来标识
¨消息队列的实现
$消息队列的实现包括创建和打开消息队列、添加消息、读取消息和控制消息队列
$创建或打开消息队列:msgget。这里创建的消息队列的数量会受到消息队列数量的
限制
$添加消息:msgsnd函数,它把消息添加到已打开的消息队列末尾
$读取消息:msgrcv,它把消息从队列中取走,与FIFO不同的是,这里可以指定取走
某一条消息
$控制消息队列:msgctl
有关的数据结构:
Øipc_perm:IPC对象的访问权限
Ømsgbuf:消息的数据类型
Ømsg:消息链表的节点结构
Ømsgqid_ds:消息队列对象的结构
消息队列相关函数: *****
#include
#include
#include
int msgget(key_t key, int flg);
入参: key:和消息队列关联的key值
flg:消息队列的访问权限
IPC_CREAT、创建新的消息队列
IPC_EXCL,与IPC_CREAT一起使用;如果要创建的消息队列已经存在,则返
回错误
IPC_NOWAIT读写消息队列要求无法得到满足时,不阻塞。
返回值: 成功 返回消息队列 ID
失败 -1
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列发送消息
入参: msqid:消息队列的ID 即msgget的返回值
msgp:指向消息的指针。常用消息结构msgbuf如下:
struct msgbuf
{
long mtype;
//消息类型
char mtext[N]
//消息正文
};
msgsz:发送的消息正文的字节数
msgflg: IPC_NOWAIT 消息没发送完立即返回
0 消息发送完成函数才会返回
返回值:
成功 0
失败 -1
int msgrcv(int msgid, void* msgp, size_t size, long msgtype, int flag); 功能: 从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。在成功读取了一条消息以后,队列中的这条消息将被删除入参: msqid:消息队列的ID
msgp:接收消息的缓冲区
size:要接收的消息的正文字节数
msgtype: 0 :接收消息队列中第一个消息
>0: 接收mtype为msgtype第一个消息
<0: 接收消息队列中mtype不小于msgtype的绝对值,
且mtype最小的消息
flag: 0: 没有收到消息就会一直阻塞
IPC_NOWAIT :没有收到消息会立即返回
返回值: 成功:接收到的消息的长度
失败:-1
int msgctl ( int msgqid, int cmd, struct msqid_ds *buf ); 入参: msqid:消息队列的队列ID
cmd: IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓
冲区中。
IPC_SET:设置消息队列的属性。这个值取自buf参数
IPC_RMID:从系统中删除消息队列。,buf 填NULL
buf:消息队列缓冲区
返回值: 成功 0
失败 -1
信号灯集(signal set):由一个或多个信号量构成的集合
#include
#include
#include
int semget(key_t key, int nsems, int semflg);//创建信号量入参: key ftok获取的key值
nsems 信号灯集中包含的信号灯数目
semflg:同消息队列
返回值: 成功:信号灯集的ID号(IPC标识符)
失败 -1
int semop ( int semid, struct sembuf *opsptr, size_t nops); 入参: semid semget的返回值,ID号
opsptr :结构体指针,指明对哪个信号灯进行操作 nops: 要操作的信号灯的个数
struct sembuf
{
short
sem_num;
//
要操作的信号灯的编号
short
sem_op;
0 :
等待,直到信号灯的值变成0
1 : 释放资源,V操作
short
sem_flg;
// 0,
-1 : 分配资源,P操作
IPC_NOWAIT, SEM_UNDO
};
返回值:
成功 0
失败 -1
int semctl ( int semid, int semnum, int cmd…/*union semun arg*/); 入参: semid: 信号灯集的ID号
semnum: 要修改的信号灯编号
cmd: GETVAL:获取信号灯的值
SETVAL:设置信号灯的值
IPC_RMID:从系统中删除信号灯集合
注意:semctl是可变参数函数:cmd为GETVAL或SETVAL时,需要传递第四个参数。参数类型为union semun
成功: 0 失败 : -1
union semun
{
int val; /* value for SETVAL */
structsemid_ds *buf;/* buffer for IPC_STAT & IPC_SET */
unsigned short*array;/* array for GETALL & SETALL */
structseminfo*__buf;/* buffer for IPC_INFO */
void *__pad;
};
头文件中的#ifndef
千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。
还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:
#ifndef <标识>
#define <标识>
......
......
#endif