消息和信号的运用都可以为任务事件驱动
不同点:
1、信号只能是固定的几个(如SIGINT),且接收对象只能是进程。而消息的对象可以是进程,也可以为线程。
2、信号不需要创建,系统是识别的,用kill -l 可以查看完整的信号列表,没有大小的讨论。消息需要申请消息队列资源,返回的是消息队列的句柄,打进的消息体长度、消息的数量、消息队列总的容量只受系统消息队列配置大小的限制。
3、消息在linux系统中,由用户层进入内核层队列,全为复制 *** 作,代价是4次拷贝。信号也需要调用系统调用,但信号本身成本低。
4、另外信号的使用会使阻塞的进程被中断掉。而消息没有这个功能。
消息队列本质上是位于内核空间的链表,链表的每个节点都是一条消息。每一条消息都有自己的消息类型,消息类型用整数来表示,而且必须大于 0。每种类型的消息都被对应的链表所维护:
其中数字 1 表示类型为 1 的消息,数字2、3、4 类似。彩色块表示消息数据,它们被挂在对应类型的链表上。
值得注意的是,刚刚说过没有消息类型为 0 的消息,实际上,消息类型为 0 的链表记录了所有消息加入队列的顺序,其中红色箭头表示消息加入的顺序。
无论你是发送还是接收消息,消息的格式都必须按照规范来。简单的说,它一般长成下面这个样子:
所以,只要你保证首4字节(32 位 linux 下的 long)是一个整数就行了。
举个例子:
从上面可以看出,正文部分是什么数据类型都没关系,因为消息队列传递的是 2 进制数据,不一定非得是文本。
msgsnd 函数用于将数据发送到消息队列。如果该函数被信号打断,会设置 errno 为 EINTR。
参数 msqid:ipc 内核对象 id
参数 msgp:消息数据地址
参数 msgsz:消息正文部分的大小(不包含消息类型)
参数 msgflg:可选项
该值为 0:如果消息队列空间不够,msgsnd 会阻塞。
IPC_NOWAIT:直接返回,如果空间不够,会设置 errno 为 EAGIN.
返回值:0 表示成功,-1 失败并设置 errno。
msgrcv 函数从消息队列取出消息后,并将其从消息队列里删除。
参数 msqid:ipc 内核对象 id
参数 msgp:用来接收消息数据地址
参数 msgsz:消息正文部分的大小(不包含消息类型)
参数 msgtyp:指定获取哪种类型的消息
msgtyp = 0:获取消息队列中的第一条消息
msgtyp >0:获取类型为 msgtyp 的第一条消息,除非指定了 msgflg 为MSG_EXCEPT,这表示获取除了 msgtyp 类型以外的第一条消息。
msgtyp <0:获取类型 ≤|msgtyp|≤|msgtyp| 的第一条消息。
参数 msgflg:可选项。
如果为 0 表示没有消息就阻塞。
IPC_NOWAIT:如果指定类型的消息不存在就立即返回,同时设置 errno 为 ENOMSG
MSG_EXCEPT:仅用于 msgtyp >0 的情况。表示获取类型不为 msgtyp 的消息
MSG_NOERROR:如果消息数据正文内容大于 msgsz,就将消息数据截断为 msgsz
程序 msg_send 和 msg_recv 分别用于向消息队列发送数据和接收数据。
msg_send 程序定义了一个结构体 Msg,消息正文部分是结构体 Person。该程序向消息队列发送了 10 条消息。
msg_send.c
程序 msg_send 第一次运行完后,内核中的消息队列大概像下面这样:
msg_recv 程序接收一个参数,表示接收哪种类型的消息。比如./msg_recv 4 表示接收类型为 4 的消息,并打印在屏幕。
先运行 msg_send,再运行 msg_recv。
接收所有消息
接收类型为 4 的消息
获取和设置消息队列的属性
msqid:消息队列标识符
cmd:控制指令
IPC_STAT:获得msgid的消息队列头数据到buf中
IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes
buf:消息队列管理结构体。
返回值:
成功:0
出错:-1,错误原因存于error中
EACCESS:参数cmd为IPC_STAT,确无权限读取该消息队列
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为msqid的消息队列已被删除
EINVAL:无效的参数cmd或msqid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行
消息队列是消息的链表,存放在内核中并有消息队列标示符标示。msgget用于创建一个新队列或打开一个现存的队列。msgsnd将新消息加入到消息队列中;每个
消息包括一个long型的type;和消息缓存;msgrcv用于从队列中取出消息;取消息很智能,不一定先进先出
①msgget,创建一个新队列或打开一个现有队列
#include
int msgget ( key_t key, int flag );
//成功返回消息队列ID;错误返回-1
②msgsnd: 发送消息
#include
int msgsnd( int msgid, const void* ptr, size_t nbytes, int flag )
//成功返回0,错误返回-1
a:
flag可以指定为IPC_NOWAIT
若消息队列已满,则msgsnd立即出错返回EABAIN;
若没指定IPC_NOWAIT; msgsnd会阻塞,直到消息队列有空间为止
③msgrcv: 读取消息:
ssize_t msgrcv( int msgid, void* ptr, size_t nbytes, long type, int flag )
a. type == 0返回消息队列中第一个消息,先进先出
b. type >0
返回消息队列中类型为tpye的第一个消息
c. type <0
返回消息队列中类型 <=
|type| 的数据;若这种消息有若干个,则取类型值最小的消息
消息队列创建步骤:
#define
MSG_FILE "."
struct msgtype {
long mtype
char buffer[BUFFER+1]
}
if((key=ftok(MSG_FILE,'a'))==-1)
{
fprintf(stderr,"Creat Key Error:%s\n", strerror(errno))
exit
(1)
}
if((msgid=msgget(key, IPC_CREAT | 0666/*PERM*/))==-1)
{
fprintf(stderr,"Creat Message
Error:%s\n", strerror(errno))
exit
(1)
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)