概述
消息的发布、订阅是应用进程进行数据交换的常用方式,对于进程没有角色限制,既可以扮演发布也可以扮演订阅角色;该模式是进程间通信的异步模式。
mq_send函数说明
函数 mq_send() 会将参数 msg_ptr 指向的内容发送给参数mqdes 指向的消息队列.
参数 msg_len 指定消息的大小(用字节数表示). 参数 msg_len 的值应该不大于消息队列的属性 mq_msgsize 的值, 否则函数执行失败.
如果指定的消息队列不为空, mq_send() 的操作类似将消息插入在消息队列的指定位置,指定位置是通过参数 msg_prio 来指定.
参数 msg_prio 值大的消息会被插入在参数 msg_prio值小的消息前;如果值相等,则插在后面. 参数 msg_prio 的值应该小于 {MQ_PRIO_MAX}.
如果指定的消息队列满了并且 O_NONBLOCK(mq_open中设置) 未被设置, 函数mq_send() 会阻塞, 一直到消息可以被插入队列或者函数 mq_send() 被信号中断.
如果有几个线程都在等待消息队列的空闲资源向, 在支持优先级调度的系统中, 优先级最高的线程先解除阻塞,如果优先级相同则等待时间最长的线程先解除阻塞;
不支持优先级调度的系统中, 哪一个等待线程解除阻塞是未说明的.
如果指定的消息队列满了并且 O_NONBLOCK被设置了,函数 mq_send() 会失败返回.
#include <mqueue.h>
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,unsigned msg_prio);
mq_receive函数说明
函数 mq_send() 会将参数 msg_ptr 指向的内容发送给参数mqdes 指向的消息队列.
参数 msg_len 指定消息的大小(用字节数表示). 参数 msg_len 的值应该不大于消息队列的属性 mq_msgsize 的值, 否则函数执行失败.
如果指定的消息队列不为空, mq_send() 的操作类似将消息插入在消息队列的指定位置,指定位置是通过参数 msg_prio 来指定.
参数 msg_prio 值大的消息会被插入在参数 msg_prio值小的消息前;如果值相等,则插在后面. 参数 msg_prio 的值应该小于 {MQ_PRIO_MAX}.
如果指定的消息队列满了并且 O_NONBLOCK(mq_open中设置) 未被设置, 函数mq_send() 会阻塞, 一直到消息可以被插入队列或者函数 mq_send() 被信号中断.
如果有几个线程都在等待消息队列的空闲资源向, 在支持优先级调度的系统中, 优先级最高的线程先解除阻塞,如果优先级相同则等待时间最长的线程先解除阻塞;
不支持优先级调度的系统中, 哪一个等待线程解除阻塞是未说明的.
如果指定的消息队列满了并且 O_NONBLOCK被设置了,函数 mq_send() 会失败返回.
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,unsigned msg_prio);
测试代码
#include <fstream>
#include <iostream>
#include <thread>
#include <vector>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
std::string kQueueName = "/test2";
class MessageQueue {
private:
mqd_t handle;
public:
MessageQueue(const std::string& name, int flags) {
handle = mq_open(name.c_str(), flags);
if (handle < 0) {
throw std::runtime_error("Failed to open a queue for writing");
}
}
MessageQueue(const std::string& name, int flags, int max_count, int max_size) {
struct mq_attr attrs = { 0, max_count, max_size, 0 };
handle = mq_open(name.c_str(), flags | O_CREAT, 0666, &attrs);
if (handle < 0) {
throw std::runtime_error("Failed to create a queue");
}
}
~MessageQueue() {
mq_close(handle);
}
void Send(const char* data, size_t len) {
if (mq_send(handle, data, len, 0) < 0) {
throw std::runtime_error("Failed to send a message");
}
}
void Receive(char* data, size_t len) {
if (mq_receive(handle, data, len, 0) < len) {
throw std::runtime_error("Failed to receive a message");
}
}
};
template<class T>
class Writer {
private:
MessageQueue queue;
public:
Writer(std::string& name):
queue(name, O_WRONLY) {}
void Write(const T& data) {
queue.Send(reinterpret_cast<const char*>(&data), sizeof(data));
}
};
template<class T>
class Reader {
private:
MessageQueue queue;
public:
Reader(std::string& name):
queue(name, O_RDONLY) {}
void Run() {
T data;
while(true) {
queue.Receive(reinterpret_cast<char*>(&data), sizeof(data));
Callback(data);
}
}
protected:
virtual void Callback(const T& data) = 0;
};
struct Message {
int x, y;
};
std::ostream& operator<<(std::ostream& o, const Message& m) {
o << "(x=" << m.x << ", y=" << m.y << ")";
}
class CoordLogger : public Reader<Message> {
using Reader<Message>::Reader;
protected:
void Callback(const Message& data) override {
std::cout << "Received coordinate " << data << std::endl;
}
};
void DoWrites() {
std::vector<Message> messages {{1, 0}, {0, 1}, {1, 1}, {0, 0}};
Writer<Message> writer(kQueueName);
for (const auto& m : messages) {
std::cout << "Write " << m << std::endl;
writer.Write(m);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void DoReads() {
CoordLogger logger(kQueueName);
logger.Run();
}
int main(int argc, char** argv) {
MessageQueue q(kQueueName, O_WRONLY, 10, sizeof(Message));
pid_t pid = fork();
if (pid) {
DoWrites();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
kill(pid, SIGTERM);
} else {
DoReads();
}
}
测试结果
我公司承接各类技术服务,主要聚焦于:stm32、单片机、嵌入式、QT应用开发、Web+Python+Django应用开发。欢迎合作。