我用 C++ 写了一个 “消息队列”类 MsgQueue ,来包装 Linux 上的消息队列操作,成员方法主要是 push (对应 msgsnd )和 pop (对应 msgrcv ),创建消息队列时没错,但在 msgsnd 和 msgrcv 时总是返回 -1 。我猜可能是把 Msg 的地址传进去时有 ABI 的问题,请知道的朋友指点一下,非常感谢!
程序如下,分别是定义消息队列的头文件,发送者,接收者以及 Makefile.
// msgqueue.h
#ifndef MSGQUEUE_H
#define MSGQUEUE_H
#include <stdexcept>
#include <string>
#include <cstring>
#include <cstdio>
#include <sys/msg.h>
struct Msg {
long type;
char text[BUFSIZ];
Msg() {};
Msg(long typ, const char *txt) : type(typ) {
strncpy(text, txt, BUFSIZ - 1);
text[BUFSIZ - 1] = '\0';
}
};
class MsgQueue {
private:
int id_;
public:
MsgQueue(key_t key = 1235) {
int id = msgget(key, IPC_CREAT);
if (id == -1) {
throw std::runtime_error("Create message queue failed.");
}
printf("Message queue's id is %d.\n", id_);
id_ = id;
}
void push(const std::string &text, long type = 1) {
push(Msg(type, text.c_str()));
}
void push(const char *text, long type = 1) {
push(Msg(type, text));
}
void push(const Msg &msg) {
if (-1 == msgsnd(id_, &msg, BUFSIZ, 0)) { // 总返回 -1
throw std::runtime_error("Send message failed.");
}
}
Msg pop(long type = 1) {
Msg msg;
if (-1 == msgrcv(id_, &msg, BUFSIZ, type, 0)) {
throw std::runtime_error("Receive message failed.");
}
return msg;
}
};
#endif
// send.cpp
#include <iostream>
#include "msgqueue.h"
int main() {
MsgQueue Q;
std::string txt = "hell";
Q.push(txt.c_str());
std::cout << "Send message: " << txt << std::endl;
return 0;
}
// recv.cpp
#include <iostream>
#include "msgqueue.h"
int main() {
MsgQueue Q;
Msg msg = Q.pop();
std::cout << "Receive message: " << msg.text << std::endl;
return 0;
}
TARGET := $(patsubst %.cpp, %, $(wildcard *.cpp))
all: $(TARGET)
%: %.cpp $(wildcard *.h)
g++ $< -std=c++14 -g -o $@
clean:
rm -fr $(TARGET)
1
matthewgao 2016-10-09 23:31:50 +08:00
-1 的时候检查下 errno 看看返回什么结果,就一目了然了,会不会是读写权限的问题
|
2
matthewgao 2016-10-09 23:32:08 +08:00
The msgsnd() and msgrcv() system calls are used, respectively, to send messages to, and receive messages from,
a System V message queue. The calling process must have write permission on the message queue in order to send a message, and read permission to receive a message. |
3
Tony8Finet 2016-10-10 23:36:25 +08:00
System V IPC 是存在于作业系统中,因此其生命周期是和作业系统一样。一但建立了并未明确移除就一直存在,直到作业系统关机或重启。
你的程式有些问题: * IPC\_CREATE 只能第一个人做 (注意存取权限),随后的人只能使用,不可再用 IPC\_CREATE: <pre><code>MsgQueue(key_t key = 1235) { int id = msgget(key, IPC_CREAT|0660); created_ = (id == 0); // private: bool created_; key_ = key; // private: key_t key_; if (!created_) { id = msgget(key, 0); if (id == -1) { throw std::runtime_error(std::string("msgget: ") + strerror(errno)); } } id_ = id; } </code></pre> * 建立者结束时要记得释放资源,若还有他人在使用中则系统会延迟到没人使用时才会释放: <pre><code>~MsgQueue() { if (created_) { // 考虑释放资源,若不在此处释放则需另行手动处理 (ipcrm) msgctl(key_, IPC_RMID, 0); } } </code></pre> 有问题时程式应检查 errno 或用 strerror(errno)。 另外 IPC 的状态检视可用命令: `ipcs -a` |