V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jjtx
V2EX  ›  C

用 C++ 包装 POSIX 消息队列是否有 ABI 问题?

  •  
  •   jjtx · 2016-10-09 21:33:58 +08:00 · 2151 次点击
    这是一个创建于 2994 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我用 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)
    
    3 条回复    2016-10-10 23:36:25 +08:00
    matthewgao
        1
    matthewgao  
       2016-10-09 23:31:50 +08:00
    -1 的时候检查下 errno 看看返回什么结果,就一目了然了,会不会是读写权限的问题
    matthewgao
        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.
    Tony8Finet
        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`
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2575 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 12:00 · PVG 20:00 · LAX 04:00 · JFK 07:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.