POSIX 行列步队 API 的紧张函数如下:
mq_open() 函数创建一个新行列步队或打开一个既有行列步队,返回后续调用中会用到的行列步队描述符mq_send() 函数向行列步队写入一条mq_receive() 函数从行列步队中读取一条mq_close() 函数关闭进程之前打开的一个行列步队mq_unlink() 函数删除一个行列步队并当所有进程关闭该行列步队时对行列步队进程标记以便删除此外,POSIX 行列步队 API 还具备一些特殊的特性:
#include <fcntl.h> / For O_ constants /#include <sys/stat.h> / For mode constants /#include <mqueue.h>mqd_t mq_open(const char name, int oflag);mqd_t mq_open(const char name, int oflag, mode_t mode,struct mq_attr attr);
mq_open() 函数创建一个新行列步队或打开一个既有行列步队name 参数标识出了行列步队oflag 参数是一个位掩码,它掌握着 mq_open() 操作的各个方面,取值如下:

嵌入式物联网须要学的东西真的非常多,千万不要学错了路线和内容,导致人为要不上去!
无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!
某鱼上买估计至少要好几十。
点击这里找小助理0元领取:加微信领取资料
oflag 参数的个中一个用场是,确定是打开一个既有行列步队还是创建和打开一个新行列步队,oflag 不包含 O_CREAT 时,那么将会打开一个既有行列步队,如果 oflag 中包含了 O_CREAT 并且给定的 name 不存在时将会创建一个新的空行列步队,如果oflag 同时包含了 O_CREAT 和 O_EXCL,并且给定的 name 对应的行列步队已经存在,那么 mq_open() 就会失落败mode 参数是一个位掩码,它指定了施加于新行列步队之上的权限attr 参数是一个 mq_attr 构造,它指定了新行列步队的特性。如果 attr 为 NULL,那么将利用实现定义的默认特性创建行列步队fork()、exec()以及进程终止对行列步队描述符的影响
在 fork() 中子进程会接管其父进程在行列步队描述符的副本,并且这些描述符会引用同样的打开的行列步队描述。子进程不会继续父进程的任何关照注册。
当一个进程实行了一个 exec() 或终止时,所有其打开的行列步队描述符会被关闭。关闭行列步队描述符的结果是进程在相应行列步队上的关照注册会被注销。
关闭一个行列步队#include <mqueue.h>int mq_close(mqd_t mqdes);
mq_close() 函数关闭了行列步队描述符 mqdes
如果调用进程已经通过 mqdes 在行列步队上注册了关照,那么关照注册会自动被删除,并且另一个进程可以随后向该行列步队注册关照。
当进程终止或者调用 exec() 时,行列步队描述符会被自动关闭。问问价描述符一样,运用程序该当在不再利用行列步队描述符的时候显示的关闭行列步队描述符以防止进程耗尽行列步队描述符的情形。
与文件上的 close() 一样,关闭一个行列步队并不会删除该行列步队。要删除行列步队必须显示的调用 mq_unlink(),它是 unlink() 在行列步队上的版本。
删除一个行列步队mq_unlink() 函数删除通过 name 标识的行列步队,并将行列步队标记为在所有进程利用完该行列步队之后销毁该行列步队。
#include <mqueue.h>int mq_unlink(const char name);
描述符和行列步队之间的关系
行列步队是一个进程级别的句柄,它引用了系统层面的打开的行列步队描述符中的一个条款,而该条款引用了一个行列步队工具,如下图:
一个打开的行列步队描述拥有一组关联的标记。SUSv3 只规定了一种这样的标记,即 NONBLOCK,它确定了 IO 是否是非壅塞的两个进程能够持有引用同一个打开的行列步队描述的行列步队描述符。当一个进程在打开了一个行列步队之后调用 fork() 时就会发生这样的情形。这些描述符会共享 O_NONBLOCK 标记的状态两个进程能够持有引用不同行列步队描述(它们引用了同一个行列步队)的打开的行列步队描述(如进程 A 中的描述符 z 和进程 B 中的描述符 y 都引用了/mq-r)。当两个进程分别利用 mq_open() 打开同一个行列步队时就会发生这种情形行列步队特性
mq_open()、mq_getattr() 以及 mq_setattr() 函数都会吸收一个参数,它是一个指向 mq_attr 构造的指针。这个构造是在 <mqueue.h> 中进行定义的,其形式如下:
struct mq_attr{ long mq_flags;/ Message queue flags. / long mq_maxmsg;/ Maximum number of messages. / long mq_msgsize;/ Maximum message size. / long mq_curmsgs;/ Number of messages currently queued. /};
在创建行列步队时设置行列步队特性
在利用 mq_open() 创建行列步队时可以通过下列 mq_attr 字段来确定行列步队的特性:
mq_maxmsg 字段定义了利用 mq_send() 向行列步队添加的数量上限,其取值必须大于0mq_msgsize 字段定义了加入行列步队的每条的大小的上限,其取值必须大于 0内核根据这两个值来确定行列步队所需的最大内存量。
mq_maxmsg 和 mq_msgsize 特性是在行列步队被创建时就确定下来的,并且之后也无法修正这两个特性。
获取消息行列步队特性#include <mqueue.h>int mq_getattr(mqd_t mqdes, struct mq_attr attr);
mq_getattr() 函数返回一个包含与描述符 mqdes 干系联的行列步队描述和行列步队的干系信息的 mq_attr 构造
除了上面已经先容的 mq_maxmsg 和 mq_msgsize 字段之外,attr 指向的返回构造中还包含下列字段:
mq_flags :其取值只有一个 O_NONBLOCK。这个标记是根据 mq_open() 的 oflag 参数来初始化的,并且利用 mq_setattr() 可以修正这个标记mq_curmsgs:这个当前位于行列步队中的数。这个信息在 mq_getattr() 返回时可能已经发生了改变,条件是存在其他进程从行列步队中读取消息或向行列步队写入修正行列步队特性#include <mqueue.h>int mq_setattr(mqd_t mqdes, const struct mq_attr newattr,struct mq_attr oldattr);
mq_setattr() 函数设置与行列步队描述符 mqdes 干系联的行列步队描述的特性,并可选地返回与行列步队有关的信息mq_setattr() 函数实行下列任务:它利用 newattr 指向的 mq_attr 构造中的 mq_flags 字段来修正与描述符 mqdes 干系联的行列步队描述的标记如果 oldattr 不为 NULL,那么就返回一个包含之前的行列步队描述标记和行列步队特性的 mq_attr 构造(即与 mq_getattr()实行的任务一样)
SUSv3 规定利用 mq_setattr() 能够修正的唯一特性是 O_NONBLOCK 标记的状态。如下代码可以启用 O_NONBLOCK:
if(mq_getattr(mqd, &attr) == -1){errExit("mq_getattr");}attr.mq_flags != O_NONBLOCK;if(mq_setattr(mqd, &attr, NULL) == -1){errExit("mq_setattr()");}
交流发送
#include <mqueue.h>int mq_send(mqd_t mqdes, const char msg_ptr,size_t msg_len, unsigned int msg_prio);
mq_send() 函数将位于 msg_ptr 指向的缓冲区中的添加到描述符 mqdes 所引用的行列步队中msg_len 参数指定了 msg_ptr 指向的的长度,其值必须小于或者即是行列步队的 mq_msgsize 特性,否则 mq_send() 就会返回EMSGSIZE 缺点。长度为零的是许可的每个行列步队都拥有一个用非负整数表示的优先级,它通过 msq_prio 指定。0表示优先级最低,数值越大优先级越高。当一个被添加到行列步队中时,他会被放置在行列步队中具有相同优先级的所有之后。如果一个运用程序无需利用优先级,那么只须要将msg_prio 指定为 0 即可SUSv3 许可一个实现为优先级规定一个上限,这可以通过定义常量 MQ_PRIO_MAX 或通过规定 sysconf(_SC_MQ_PRIO_MAX) 的返回值来完成如果行列步队已经满了(即已经达到了行列步队的 mq_maxmsg 限定),那么后续的 mq_send() 调用会壅塞直到行列步队中存在可用空间为止或者在 O_NONBLOCK 标记起浸染时立即失落败并返回 EAGAIN 缺点吸收
#include <mqueue.h>ssize_t mq_receive(mqd_t mqdes, char msg_ptr,size_t msg_len, unsigned int msg_prio);
mq_receive() 从 mqdes 引用的行列步队中删除一条优先级最高、存在韶光最长的并将删除的放置在 msq_ptr 指向对的缓冲区调用者通过 msq_len 指定 msg_ptr 指向的缓冲区中可用字节数不管的实际大小是什么,msg_len(即 msg_ptr 指向的缓冲区的大小)必须要大于或即是行列步队的 mq_msgsize 特性,否则 mq_receive() 就会失落败并返回 EMSGSIZE 缺点如果 msg_prio 不为 NULL,那么吸收到的的优先级会被复制到 msg_prio 指向的位置处如果行列步队当前为空,那么 mq_receive() 会壅塞直到存在可用的或在 O_NONBLOCK 标记起浸染时会立即失落败并返回 EAGAIN 缺点在发送和吸收时设置超时时间
#include <time.h>#include <mqueue.h>int mq_timedsend(mqd_t mqdes, const char msg_ptr,size_t msg_len, unsigned int msg_prio,const struct timespec abs_timeout);ssize_t mq_timedreceive(mqd_t mqdes, char msg_ptr,size_t msg_len, unsigned int msg_prio,const struct timespec abs_timeout);
mq_timedsend() 和 mq_timedreceive() 函数与 mq_send() 和 mq_receive() 险些是完备一样的,它们之间唯一的差别在于如果操作无法立即被实行,并且该行列步队描述上的 O_NONBLOCK 标记不起浸染,那么 abs_timeout 参数就会为调用壅塞的韶光指定一个上限如果 mq_timedsend() 或 mq_timedreceive() 调用因超时而无法完成操作,那么调用就会失落败并返回 ETIMEDOUT 缺点在 Linux 年夜将 abs_timeout 指定为 NULL 表示永久不会超时,但这种行为并没有在 SUSv3中得到规定,因此可移植的运用程序不应该依赖这种行为关照
POSIX 行列步队差异于 System V 行列步队的一个特性是 POSIX 行列步队能够吸收之前为空的行列步队上有可用的异步关照(即行列步队从空变成了非空)。这个特性意味着已经无需指向一个壅塞的调用或者将行列步队描述符标记为非壅塞并在行列步队上定期指向 mq_receive() 了,进程可以选择通过旗子暗记的形式或者通过在一个单独的线程中调用一个函数的形式来接管关照。
mq_notify() 函数注册调用进程在一条进入描述符 mqdes 引用的空行列步队时吸收关照:
#include <mqueue.h>int mq_notify(mqd_t mqdes, const struct sigevent sevp);
在任意时候都只有一个进程(“注册进程”)能够向一个特定的行列步队注册吸收关照。如果一个行列步队上已经存在注册线程了,那么后续在该行列步队上的注册要求将会失落败(mq_notify() 返回 EBUSY 缺点)只有当一条新进入空行列步队时才会发送关照。如果行列步队不空就不会发送关照当向注册进程发送一个关照之后就会删除注册,之后任何进程就能够向行列步队注册吸收关照了。换句话说,只要一个进程想要持续的吸收关照,那么它就必须要在每次吸收关照之后再次调用 mq_notify() 注书籍身注册进程只有在当前不存在其他在该行列步队上调用 mq_receive() 而发生壅塞的进程时才会收到关照。如果其他进程在 mq_receive()调用中被壅塞了,那么该进程会读取消息,注册进程会保持注册状态一个进程可以通过在调用 mq_notify() 时传入一个值为 NULL 的 notification 参数来撤销自己在关照上的注册信息
sigevent 中与 mq_notify() 干系的字段:
union sigval{int sival_int;void sival_ptr;};struct sigevent{int sigev_notify;int sigev_signo;union sigval sifev_value;void (sigev_notify_function)(union sigval);void sigev_notify_attributes;};
sigev_notify 字段将会被设置成下列值中的一个SIGEV_NONE:注册这个进程吸收关照,但当一条进入空行列步队时不通知该进程。与往常一样,当新进入空行列步队之后注册信息会被删除SIGEV_SIGNAL:通过天生一个在 sigev_signo 字段中指定的旗子暗记来关照进程。如果 sigev_signo 是一个实时旗子暗记,那么sigev_value 字段将会指定旗子暗记都带的数据。通过传入旗子暗记处理器的 siginfo_t 构造中的 si_value 字段或通过调用 sigwaitinfo() 或 sigtimedwait() 返回值能够取得这部分数据。siginfo_t 构造中的下列字段也会被添补:si_code,其值为 SI_MESGQ;si_signo,其值是旗子暗记编号;si_pid,其值是发送的进程的进程 ID;以及 si_uid,其值是发送的进程的真实用户 ID。(si_pid 和 si_uid 字段在其他大多数实现上不会被设置SIGEV_THREAD:通过调用在 sigev_notify_function 中指定的函数来关照进程,就像是在一个新线程中启动该函数一样。sigev_notify_attributes 字段可以为 NULL 或是一个指向定义了线程的特性的 pthread_ attr_t 构造的指针。sigev_value 中指定的联合 sigval 值将会作为参数传入这个函数Linux 特有的特性
POSIX 行列步队在 Linux 上的实现供应了一些非标准的却相称有用的特性。
通过命令行显示和删除行列步队工具POSIX IPC 工具被实现成了虚拟文件系统中的文件,并且可以利用 ls 和 rm 来列出和删除这些文件。为列出和删除 POSIX 行列步队就必须要利用乤命令来将行列步队挂载到文件系统中:
mount -t mqueue source target
source 可以是任意一个名字(常日将其指定为字符串 none),其唯一的意义是它将涌如今 /proc/mounts 中并且 mount 和 df 命令会显示出这个名字。target 是行列步队文件系统的挂载点。
下面的 shell 会话显示了如何挂载行列步队文件系统和显示其内容。首先为文件系统创建一个挂载点并挂载它:
$ su$ mkdir /dev/mqueue$ mount -t mqueue node /dev/mqueue$ exit$ cat /proc/mounts | grep mqueuenode /dev/mqueue mqueue rw,relatime 0 0$ ls -ld /dev/mqueuedrwxr-xr-x 2 root root 0 Aug 9 21:28 /dev/mqueue
获取消息行列步队的干系信息
cat /dev/mqueue/mqQSIZE:7NOTIFY:0 SIGNO:0NOTIFY_PID:0
QSIZE 字段的值为行列步队中所有数据的总字节数,剩下的字段则与关照干系,如果 NOTIFY_PID 为非零,那么进程 ID 为该值得进程已经向该行列步队注册吸收关照剩下的字段则这种关照干系的信息。
NOTIFY 是一个与个中一个 sigev_notify 常量对应的值:0 表示 SIGEV_SIGNAL1 表示 SIGEV_NONE2 表示 SIGEV_THREAD如果关照办法是 SIGEV_SIGNAL,那么 SIGNO 字段指出了哪个旗子暗记会用来分发关照利用另一种 I/O 模型操作行列步队在 Linux 中,行列步队描述符实际上是一个文件描述符,因此可以利用 IO 多路复用系统调用(select() 和 poll())或 epoll() API 来监控这个文件描述符。
行列步队限定SUSv3 为 POSIX 行列步队定义了两个限定:
MQ_PRIO_MAX:定义了一条的最大优先级MQ_OPEN_MAX:一个实现可以定义这个限定来指明一个进程最多能打开的行列步队数量。SUSv3 哀求这个限定最小为_POSIX_MQ_OPEN_MAX(8)。Linux 并没有定义这个限定,相反,由于 Linux 将行列步队描述符实现成了文件描述符,因此适用于文件描述符的限定将适用于行列步队描述符。(换句话说,在 Linux 上,每个进程以及系统所能打开的文件描述符的数量限定实际上会运用于文件描述符数量和行列步队描述符数量之和。)下面这三个文件位于 /proc/sys/fs/mqueue 目录中:
msg_max:这个限定为新行列步队的 mq_maxmsg 特性的取值规定了一个上限,默认值是 10,最小值是1,最大值由内核常量 HARD_MSGMAX 定义msgsize_max:这个限定为非特权进程创建的新行列步队的 mq_msgsize 特性的取值规定了一个上限(即利用 mq_open() 创建行列步队时 attr.mq_msgsize 字段的上限值 ),默认值是 8192最小值是 128,当一个非特权进程 CAP_SYS_RESOURCE 调用 mq_open() 时会忽略这个限定queues_max:这是一个别系级别的限定,它规定了系统上最多能够创建的行列步队的数量,一旦达到这个限定,就只有特权进程 CAP_SYS_RESOURCE 才能够创建新行列步队,默认值是 256,取值范围是 [0,INT_MAX]POSIX 和 System V 行列步队比较POSIX 行列步队与 System V 行列步队的相似之处在于数据的交流单位是全体,但它们之间存在一些显著的差异:
POSIX 行列步队是引用计数的。只有当所有当前利用行列步队的进程都关闭了之后才会对行列步队进程标记以便删除每个 System V 都有一个整数类型,并且通过 msgrcv() 可以以各种办法选择。而 POSIX 由一个管理的优先级,并且之间是严格按照优先级顺序排队(以及吸收)的POSIX 行列步队供应了一个特性许可在行列步队中的一条可用时异步的关照进程POSIX 关照特性运行一个进程能够在一条进入空行列步队时异步关照旗子暗记或者线程的实例化来接管关照在Linux上可以利用 poll、select、epoll 来监听 POSIX 行列步队。System V 没有这个特性但与 System V 行列步队比较,POSIX 行列步队也具备以下劣势:
POSIX 行列步队的可移植性稍差与 POSIX 行列步队严格按照优先级排序比较,System V 行列步队能够根据类型来选择的功能的灵巧性更强。POSIX 行列步队支持是一个通过 CONFIG_POSIX_MQUEUE 选项配置的可选内核组件。
往期精彩linux驱动开拓中与设备树干系的6种debug方法
嵌入式Linux QT开拓之如何实现获取磁盘空间大小的运用逻辑
嵌入式Linux MIPI接口LCD调试-关于DRM显示与运用调试的干货浓缩
基于瑞芯微RV1109 Linux触摸屏GT911驱动调试心得(二)-设备树刷厂商给的触摸屏固件
转载自:嵌入式运用研究院
文章来源于Linux Posic行列步队和System V行列步队的差异
原文链接:https://mp.weixin.qq.com/s/j3IgF68NAZB3vhrSbmHuzQ