Named Message Queue Interfaces
命名消息队列的接口
NuttX支持POSIX命名消息队列inter-task通讯。任何任务都能能通过命名消息队列发送或接收消息。中断处理程序可以通过命名消息队列发送消息。我理解就是进程之间通讯需要一个消息通道,消息队列就是这样一个通道,而其标识就是这个“Named”。
mq_open
mqd_t mq_open(const char *mqName, int oflags, …);
调用这个函数将与一个消息队列链接。
oflags:
oflags | 意义 |
---|---|
O_RDONLY | 读访问 |
O_WRONLY | 写访问 |
O_RDWR | 读和写 |
O_CREAT | 如果不存在时创建消息队列。 |
O_EXCL | 打开时名称必须不存在 |
O_NONBLOCK | 不要等待数据。 |
.
这是一个参数数量可变的函数,根据头文件中的描述,当 O_CREAT
这个oflags被使用时,该函数将另外需要两个参数:mode_t mode
和 struct mq_attr *attr
。
mode 这里说的是权限,就像在Linux中文件的权限一样。相关定义:
#define S_IXOTH| 0000001 /* Permissions for others: Run only */
#define S_IWOTH 0000002 /* Permissions for others: Write only */
#define S_IROTH 0000004 /* Permissions for others: Read only */
#define S_IRWXO 0000007 /* Permissions for others: All */
#define S_IXGRP 0000010 /* Group permissions: Run only */
#define S_IWGRP 0000020 /* Group permissions: Write only */
#define S_IRGRP 0000040 /* Group permissions: Read only */
#define S_IRWXG 0000070 /* Group permissions: All */
#define S_IXUSR 0000100 /* Owner permissions: Run only */
#define S_IWUSR 0000200 /* Owner permissions: Write only */
#define S_IRUSR 0000400 /* Owner permissions: Read only */
#define S_IRWXU 0000700 /* Owner permissions: All */
struct mq_attr *attr
可以找到定义:
struct mq_attr {
size_t mq_maxmsg; /* Max number of messages in queue */
size_t mq_msgsize; /* Max message size */
unsigned mq_flags; /* Queue flags */
size_t mq_curmsgs; /* Number of messages currently in queue */
};
看起来是一些属性。
*我决定每一个函数函数后都加上测试,然后发现这个直接上来就写有点难,然后全工程搜索,发现了一个叫ostest的例子。细细一看,尽然包含了之前所有的函数,简直没天理啊。。将其下mqueue.c文件中的代码拷过来,加个宏定义居然就能用了。我先试试开启这个例子把。结果是完全能用,真后悔没有早点发现这个例子。有空把前面的坑全都补上。包括那个等待所有子进程的坑。所有有关进程锁,消息队列的例子代码都在这个ostest
里面*
mq_close
int mq_close(mqd_t mqdes);
这个函数是用来表明调用任务已经完成了指定描述符的消息排队。mq_close()收回分配任何系统资源分配的系统消息队列使用的这个任务。
简单的来说就是关闭消息队列。通过参数也就是消息队列的描述符。
mq_unlink
int mq_unlink(const char *mqName);
这个函数使用来删除消息队列,如果消息队列已经被打开,那么将等到其被关闭时再删除。
mq_send
int mq_send(mqd_t mqdes, const void *msg, size_t msglen, int prio);
这个函数将一个大小为msglen bytes
的信息(由msg
指向的字符串)添加到由消息队列描述符mqdes
指定的消息队列中。最大长度不得超过由mq_getattr()
获得的长度。这里,mq_getattr()
返回的是一个结构体:
struct mq_attr {
size_t mq_maxmsg; /* Max number of messages in queue */
size_t mq_msgsize; /* Max message size */
unsigned mq_flags; /* Queue flags */
size_t mq_curmsgs; /* Number of messages currently in queue */
};
这里所指的是成员mq_msgsize
。
这里对应三种情况:
- 如果消息队列未满,函数将信息插入消息队列中优先级为
prio - 1
的消息的前面。 - 如果消息队列已满,并且
O_NONBLOCK
没有置位,那么函数将阻塞,直到消息队列有地方可存放。 - 如果消息队列已满,并且
O_NONBLOCK
置位,那么函数将返回错误。
正确返回OK
;错误返回ERROR
并返回错误代码:
errno | 详细 |
---|---|
EAGAIN | 消息队列为空,且O_NONBLOCK 置位 |
EINVAL | 参数有错 |
EPERM | 消息队列打开方式不可写 |
EMSGSIZE | 长度超出 |
EINTR | 调用时被中断 |
.
mq_receive
ssize_t mq_receive(mqd_t mqdes, void *msg, size_t msglen, int *prio);
函数将接受最高优先级中存放时间最久的信息。如果msg
指向的空间不足以存放信息,那么函数将返回错误。否则,信息将从队列中移动到msg
指向的空间内。
如果队列为空且O_NONBLOCK
没有置位,那么函数将锁定直到队列中有信息。如果有很多任务在等待,那么只有等待时间最久的优先级最高的任务才能解锁。
如果队列为空且O_NONBLOCK
置位,那么函数将返回错误和错误参数。
errno | 详细 |
---|---|
EAGAIN | 消息队列为空,且O_NONBLOCK 置位 |
EPERM | 消息队列打开方式不可写 |
EMSGSIZE | 长度超出 |
EINTR | 调用时被中断 |
EINVAL | 参数有错 |
.
mq_timedreceive
ssize_t mq_timedreceive(mqd_t mqdes, void *msg, size_t msglen, int *prio, const struct timespec *abstime);
函数将接受最高优先级中存放时间最久的信息。如果msg
指向的空间不足以存放信息,那么函数将返回错误。否则,信息将从队列中移动到msg
指向的空间内。
如果队列为空且O_NONBLOCK
没有置位,那么函数将锁定直到队列中有信息。如果有很多任务在等待,那么只有等待时间最久的优先级最高的任务才能解锁。
唯一一点不同的是,如果O_NONBLOCK
没有被启用,那么函数将会等待一段时间,由结构体abstime
来确定,之后没有消息的话将立刻返回。
注意:这里是绝对时间。要先获取当前系统时间,然后在加上需要等待的时间。
errno | 详细 |
---|---|
EAGAIN | 消息队列为空,且O_NONBLOCK 置位 |
EPERM | 消息队列打开方式不可写 |
EMSGSIZE | 长度超出 |
EINTR | 调用时被中断 |
EINVAL | 参数有错 |
ETIMEDOUT | 超时 |
.
mq_notify
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
调用该函数的任务将注册为接受消息队列(由消息队列描述符mqdes
指定)的通知。
如果notification
输入参数不为NULL
,当消息队列从空状态变为非空状态时,函数将发送一个信号到注册该消息队列通知的任务。
如果notification
输入参数为NULL
,那么已存在的注册将被分离(如果当前进程已经注册为接收指定队列的通知),消息队列将可用于注册为其他信号。
当信号notification
被发送至进程后,该注册将被移除,消息队列可用于新的注册。
notification
由实时信号结构体sigevent
定义:
struct sigevent {
uint8_t sigev_notify; /* Notification method: SIGEV_SIGNAL, SIGEV_NONE, or SIGEV_THREAD */
uint8_t sigev_signo; /* Notification signal */
union sigval sigev_value; /* Data passed with notification */
};
这里解释一下:
sigev_notify | 意义 |
---|---|
SIGEV_SIGNAL | 将sigev_signo 发送到进程 |
SIGEV_NONE | 空的通知 |
SIGEV_THREAD | 根据后面的定义看起来,该方法没有效果或者不可用,先忽略 |
.
由于这个ostest
很重要,就先写到这里。有机会再补。