管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道 (named pipe): 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( sinal ): 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
套接字( socket ) :socket既可以用于同设备进程间通信,也可用于不同设备进程间通信。
Ø 一个进程向消息队列写入消息之前,并不需要某个进程在该队列上等待该消息的到达,而管道和FIFO是相反的,进程向其中写消息时,管道和FIFO必须已经打开来读,否则写进程就会阻塞(默认情况下)。
Ø IPC的持续性不同。管道和FIFO是随进程的持续性,当管道和FIFO最后一次关闭发生时,仍在管道和FIFO中的数据会被丢弃。消息队列是随内核的持续性,即一个进程向消息队列写入消息后,然后终止,另外一个进程可以在以后某个时刻打开该队列读取消息。只要内核没有重新自举,消息队列没有被删除。
消息队列中的每条消息通常具有以下属性:
Ø 一个表示优先级的整数;
Ø 消息的数据部分的长度;
Ø 消息数据本身;
对Posix消息队列的读取总是返回最高优先级的最早消息; 对System V消息队列的读则可以返回任意指定优先级的消息。
当往一个空队列放置一个消息时, Posix消息队列允许产生一个信号或者启动一个线程; System V则不提供类似机制。
函数原型
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
struct mq_attr{
long mq_flags;
long mq_maxmsg;
long mq_msgsize;
long mq_curmsgs;
};
当第四个参数为空指针时,就使用默认属性。
当指向mq_attr结构的指针作为参数时,允许我们在该函数的实际操作时创建一个新队列时,给它指定mq_maxmsg和mq_msgsize属性. mq_open忽略该结构的另外两个成员.
(1)attr.mq_maxmsg 不能超过文件 /proc/sys/fs/mqueue/msg_max 中的数值;
(2)attr.mq_msgsize不能超过 /proc/sys/fs/mqueue/msgsize_max 的数值;
(3)消息队列名称前面必须加上斜杆。
在POSIX消息队列中 msg_max 默认为 10 ,msgsize_max 默认为8192 ,否则会报错!!!
查看当前配置:
/proc/sys/fs/mqueue# cat msg_max
/proc/sys/fs/mqueue# cat msgsize_max
修改的话,要使用:echo 1000 > /proc/sys/fs/mqueue/msg_max
一个进程在发送和接收消息之前,需要了解消息对象的属性,如消息的最大长度。以便
设定接收和发送的buffer大小。
mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr);
参数:
Mqdes:打开消息队列时获取的描述符。
Attr:指向结构struct mq_attr的指针,用来获取消息队列的四个属性
struct mq_attr {
long mq_flags; // 0或者O_NONBLOCK
long mq_maxmsg; //队列中包含的消息数的最大限制数
long mq_msgsize; //每个消息大小的最大限制数
long mq_curmsgs; //当前队列中的消息数
}
我们可以设置消息队列的属性,实际只能设置flag标志,说明队列中没有消息时,接收消息的进程是否在队列上继续等待。
mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
参数:
Mqdes:打开消息队列时获取的描述符。
Attr:指向结构struct mq_attr的指针,用来获取消息队列的最大消息个数和最大消息长
度。放到数据结构的mq_maxmsg和mq_msgsize中。
struct mq_attr {
long mq_flags; // 0或者O_NONBLOCK,只能设置这个
long mq_maxmsg; //队列中包含的消息数的最大限制数
long mq_msgsize; //每个消息大小的最大限制数
long mq_curmsgs; //当前队列中的消息数
}
oldattr:用来保存设置之前的attr值,可以为NULL.
mq_setattr只能更改mq_flags,剩余三项参数被忽略,只能在mq_open时指定.
进程在打开消息队列后,可以使用下面的函数发送消息
int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);
参数:
mqdes: 打开消息队列时获得的描述符。
ptr: 指向发送缓冲区的指针,发送缓冲区存放了要发送的数据。
Len: 要发送的数据的长度,必须小于open时指定的mq_msgsize。
prio :消息的优先级;它是一个小于MQ_PRIO_MAX 的数,数值越大,优先级越高。
POSIX 消息队列在调用 mq_receive 时总是返回队列中 最高优先级的最早消息 。如果消息不需要设定优先级,那么可以在 mq_send 是置 prio 为 0 , mq_receive 的 prio 置为 NULL 。 返回值:发送成功,返回0,失败,返回-1.
进程在打开消息队列后,可以使用下面的函数接收消息。
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *prio);
参数:
mqdes: 打开消息队列时获得的描述符。
ptr: 指向接收缓冲区的指针。接收缓冲区用来存放收到的消息。
Len: 接收缓冲区的长度。 len不能小于mq_msgsize,否则会返回EMSGSIZE
prio :消息的优先级;它是一个小于 MQ_PRIO_MAX 的数,数值越大,优先级越高。 POSIX 消息队列在调用 mq_receive 时总是返回队列中 最高优先级的最早消息 。如果消息不需要设定优先级,那么可以在 mq_send 是置 prio 为 0 , mq_receive 的 prio 置为 NULL 。 返回值: 接收成功,返回0,失败,返回-1.
mqd_t mq_close(mqd_t mqdes);
关闭消息队列,但并不删除它 成功返回0,失败返回-1
mqd_t mq_unlink(const char *name);
每个消息队列有一个保存其当前打开着描述符数的引用计数器:
当一个消息队列引用计数大于0时, 其name就能删除, 但是该队列的析构要到最后一个mq_close发生时才进行,又因为Posix消息队列具备随内核的持续性, 即使当前没有打开着的消息队列, 该队列以及其上的各个消息也将一直存在, 直到调用mq_unlink并让它的引用计数达到0以删除该队列为止
int mq_notify(mqd_t mqdes, const struct sigevent *sevp);
On success mq_notify() returns 0; on error, -1 is returned, with errno set to indicate the error.
Posix消息队列允许异步事件通知,以告知何时有一个消息放置到了某个空消息队列中,以下两种方式可选:
1. 产生一个信号
2. 创建一个线程来执行指定函数
参考https://blog.csdn.net/u012062760/article/details/47043865
*sevp定义如下:
union sigval { /* Data passed with notification */
int sival_int; /* Integer value */
void *sival_ptr; /* Pointer value */
};
struct sigevent {
int sigev_notify; /* Notification method */
int sigev_signo; /* Notification signal */
union sigval sigev_value; /* Data passed with
notification */
void (*sigev_notify_function) (union sigval);
/* Function used for thread
notification (SIGEV_THREAD) */
void *sigev_notify_attributes;
/* Attributes for notification thread
(SIGEV_THREAD) */
pid_t sigev_notify_thread_id;
/* ID of thread to signal (SIGEV_THREAD_ID) */
};
sigev_notify可以为SIGEV_NONE、SIGEV_SIGNAL、SIGEV_THREAD 。
如果设为SIGEV_NONE,则表示仅注册了当前队列的消息通知,当空消息队列收到数据时,并不给注册进程发送信号;
如果设为SIGEV_SIGNAL, 则将发送sigev_signo所指定的信号;
如果设为SIGEV_THREAD,则将启动新线程执行sigev_notify_function函数。
只允许有一个进程注册一个消息队列的通知。
如果sevp为NULL,则表示当前进程注销此mq的消息通知,允许其他进程注册此mq的通知。
如果同时有进程使用mq_receive在等待消息队列数据,则mq_receive优先于mq_notify注册的进程。
mq_notify注册的消息通知只生效一次,当收到mq消息通知时,如果还想继续收到mq消息通知,则必须重新调用mq_notify注册。
man例子:
EXAMPLE
The following program registers a notification request for the message queue named in its command-line argument.
Notification is performed by creating a thread. The thread executes a function which reads one message from the
queue and then terminates the process.
Program source
#include
#include
#include
#include
#include
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void /* Thread start function */
tfunc(union sigval sv)
{
struct mq_attr attr;
ssize_t nr;
void *buf;
mqd_t mqdes = *((mqd_t *) sv.sival_ptr);
/* Determine max. msg size; allocate buffer to receive msg */
if (mq_getattr(mqdes, &attr) == -1)
handle_error("mq_getattr");
buf = malloc(attr.mq_msgsize);
if (buf == NULL)
handle_error("malloc");
nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
if (nr == -1)
handle_error("mq_receive");
printf("Read %zd bytes from MQ\n", nr);
free(buf);
exit(EXIT_SUCCESS); /* Terminate the process */
}
int
main(int argc, char *argv[])
{
mqd_t mqdes;
struct sigevent sev;
if (argc != 2) {
fprintf(stderr, "Usage: %s \n" , argv[0]);
exit(EXIT_FAILURE);
}
mqdes = mq_open(argv[1], O_RDONLY);
if (mqdes == (mqd_t) -1)
handle_error("mq_open");
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = tfunc;
sev.sigev_notify_attributes = NULL;
sev.sigev_value.sival_ptr = &mqdes; /* Arg. to thread func. */
if (mq_notify(mqdes, &sev) == -1)
handle_error("mq_notify");
pause(); /* Process will be terminated by thread function */
}
参考:
https://www.cnblogs.com/linuxbug/p/4872496.html
https://blog.csdn.net/sty23122555/article/details/51132158
管道介绍:
http://www.cnblogs.com/linuxbug/p/4863724.html