C FreeBSD不';t在fork上保留POSIX消息队列描述

C FreeBSD不';t在fork上保留POSIX消息队列描述,c,linux,message-queue,freebsd,C,Linux,Message Queue,Freebsd,我有一个测试程序: #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <mqueue.h> #include <errno.h> #include <fcntl.h> int main() { struct mq_attr attrs; attrs.mq_maxmsg =

我有一个测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <mqueue.h>
#include <errno.h>
#include <fcntl.h>

int main() {
  struct mq_attr attrs;
  attrs.mq_maxmsg = 10;
  attrs.mq_msgsize = sizeof(int);

  const char name[] = "/test-queue";

  mqd_t q = mq_open(name, O_CREAT | O_RDWR, 0600, &attrs);
  if (q == (mqd_t)-1) {
    perror("mq_open");
    exit(EXIT_FAILURE);
  }

  mq_unlink(name); // it doesn't matter if I do this at the end or not

  if (fork()) {
    int msg = 666;
    if (mq_send(q, (const char *)&msg, sizeof(msg), 1)) {
      perror("mq_send");
      exit(EXIT_FAILURE);
    }
  } else {
    int msg;
    unsigned priority;
    if (mq_receive(q, (char *)&msg, sizeof(msg), &priority) == -1) {
      perror("mq_receive");
      exit(EXIT_FAILURE);
    }
    printf("%d\n", msg);
  }

  mq_close(q);

  return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(){
结构mq_attr attrs;
attrs.mq_maxmsg=10;
attrs.mq_msgsize=sizeof(int);
常量字符名称[]=“/test queue”;
mqd_t q=mq_open(name、O_CREAT、O|u RDWR、0600和attrs);
如果(q==(mqd_t)-1){
perror(“mq_open”);
退出(退出失败);
}
mq_unlink(name);//不管我最后是否这样做
if(fork()){
int msg=666;
if(mq_发送(q,(const char*)&msg,sizeof(msg),1)){
perror(“mq_发送”);
退出(退出失败);
}
}否则{
int-msg;
未签名优先级;
if(mq_receive(q,(char*)&msg,sizeof(msg),&priority)=-1){
perror(“mq_接收”);
退出(退出失败);
}
printf(“%d\n”,msg);
}
mq_关闭(q);
返回0;
}
我在两个平台上使用
gcc-std=c99-Wall-o mqtest mqtest.c-lrt
编译此程序:

  • Linux Kallikanzard desktop 3.8.0-31-generic 46 Ubuntu SMP周二9月10日20:03:44 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
  • FreeBSD bsd.localhost 9.2-RELEASE FreeBSD 9.2-RELEASE#0 r255898:Thu Sep 26 22:50:31 UTC 2013root@bake.isc.freebsd.org:/usr/obj/usr/src/sys/GENERIC amd64
在Linux上,一切正常。在FreeBSD上,我得到
mq\u receive:Bad file descriptor
。将
mq\u unlink
调用移动到
main()
的末尾没有帮助。有没有办法解决这个问题,或者我必须推迟标记要删除的队列并在分叉后重新打开它?

FreeBSD保留消息队列描述符。请参阅mq_open(2):

FreeBSD实现了基于文件描述符的消息队列。描述符由fork(2)之后的子级继承。描述符在exec(3)之后的新映像中关闭。消息队列描述符支持select(2)和kevent(2)系统调用

编辑

mqd_t
指向的结构确实包含描述符。但是如果您使用
fcntl()
fork()
之后测试该文件描述符,它也会返回EBADF


这是FreeBSD中的一个bug。但是我不能说缺陷是在文档中还是在实现中。

您自己试过了吗?对我来说,在子进程中重新打开消息队列是有帮助的解决方法,因此我怀疑父进程取消链接是问题所在。POSIX
fork()
指定:子进程应该有父进程的消息队列描述符的自己副本。子级的每个消息描述符应引用与父级的相应消息描述符相同的打开消息队列描述。关于:
mq_unlink()
,POSIX规定:如果调用mq_unlink()时一个或多个进程打开了消息队列,应推迟销毁消息队列,直到关闭对消息队列的所有引用。POSIX标准可在以下位置查看: