C++ OSX与Linux上的AIO-为什么它不';不能在Mac OS X 10.6上工作

C++ OSX与Linux上的AIO-为什么它不';不能在Mac OS X 10.6上工作,c++,aio,aio-write,C++,Aio,Aio Write,我的问题很简单。为什么下面的代码可以在Linux上运行,而不能在Mac OS X 10.6.2 Snow Leopard上运行 要编译,请将文件保存到aio.cc,并在Linux上使用g++aio.cc-o aio-lrt进行编译,在Mac OS X上使用g++aio.cc-o aio进行编译。我在Mac上使用Mac OS X 10.6.2进行测试,在Linux上使用Linux内核2.6进行测试 我在OSX上看到的失败是aio_write在-1下失败,并将errno设置为EAGAIN,这意味着“

我的问题很简单。为什么下面的代码可以在Linux上运行,而不能在Mac OS X 10.6.2 Snow Leopard上运行

要编译,请将文件保存到aio.cc,并在Linux上使用
g++aio.cc-o aio-lrt
进行编译,在Mac OS X上使用
g++aio.cc-o aio
进行编译。我在Mac上使用Mac OS X 10.6.2进行测试,在Linux上使用Linux内核2.6进行测试

我在OSX上看到的失败是aio_write在-1下失败,并将errno设置为EAGAIN,这意味着“资源暂时不可用”。为什么呢

extern "C" {
#include <aio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
}
#include <cassert>
#include <string>
#include <iostream>

using namespace std;

static void
aio_completion_handler(int signo, siginfo_t *info, void *context)
{
  using namespace std;
  cout << "BLAH" << endl;
}


int main()
{
  int err;

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(sin));

  sin.sin_port = htons(1234);
  sin.sin_addr.s_addr = inet_addr("127.0.0.1");
  sin.sin_family = PF_INET;

  int sd = ::socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (sd == -1) {
    assert(!"socket() failed");
  }

  const struct sockaddr *saddr = reinterpret_cast<const struct sockaddr *>(&sin);
  err = ::connect(sd, saddr, sizeof(struct sockaddr));
  if (err == -1) {
    perror(NULL);
    assert(!"connect() failed");
  }

  struct aiocb *aio = new aiocb();
  memset(aio, 0, sizeof(struct aiocb));

  char *buf = new char[3];
  buf[0] = 'a';
  buf[1] = 'b';
  buf[2] = 'c';
  aio->aio_fildes = sd;
  aio->aio_buf = buf;
  aio->aio_nbytes = 3;

  aio->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
  aio->aio_sigevent.sigev_signo = SIGIO;
  aio->aio_sigevent.sigev_value.sival_ptr = &aio;

  struct sigaction sig_act;

  sigemptyset(&sig_act.sa_mask);
  sig_act.sa_flags = SA_SIGINFO;
  sig_act.sa_sigaction = aio_completion_handler;

  sigaction(SIGIO, &sig_act, NULL);

  errno = 0;
  int ret = aio_write(aio);
  if (ret == -1) {
    perror(NULL);
  }  
  assert(ret != -1);  
}
extern“C”{
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
}
#包括
#包括
#包括
使用名称空间std;
静态空隙
aio_完成处理程序(int signo、siginfo_t*info、void*context)
{
使用名称空间std;
cout aio_buf=buf;
aio->aio\u nbytes=3;
aio->aio_sigevent.sigev_notify=sigev_信号;
aio->aio_sigevent.sigev_signo=SIGIO;
aio->aio_sigevent.sigev_value.sival_ptr=&aio;
结构信号动作信号动作;
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags=sa_SIGINFO;
sig_act.sa_sigaction=aio_completion_handler;
sigaction(SIGIO和sig_act,NULL);
errno=0;
int-ret=aio_-write(aio);
如果(ret==-1){
perror(空);
}  
断言(ret!=-1);
}

更新(2010年2月):OSX根本不支持套接字上的AIO。真倒霉

我的代码与您在10.6.2上的代码非常相似(但写入文件),工作时没有任何问题,因此可以执行您正在尝试的操作

出于好奇,SIGIO常量的值是多少? 我发现OSX中的一个无效值会导致所有写操作失败,所以 我总是通过信号1


也许可以检查sigaction()的返回值以验证信号详细信息?

在链接中提出的点都指向一种不同的方法来提出io完成通知(例如,kqueue,这是一种BSD特有的机制),但并不能真正回答您关于异步io POSIX方法的问题。以及他们是否对达尔文有用

UNIX世界真的是一堆解决方案,如果有一个经过尝试和测试的解决方案可以跨所有平台工作,那将是非常好的,可惜目前还没有——POSIX是一个旨在实现最大一致性的解决方案

这有点冒险,但在套接字句柄上设置非阻塞(即设置套接字选项O_非阻塞)以及使用SIGUSR1也可能有用

如果我有时间,我会和你的插座样品一起工作,看看我是否也能从中得到什么


祝您好运。

OSX允许您通过(CF)运行循环使用套接字。或者从runloop获取回调。 这是我发现的在mac上使用异步IO的最优雅的方式。 您可以使用现有套接字并使用Native执行CFSocketCreateWithNative。并在runloop上注册回调

这里是一个小代码片段,它展示了如何设置它,因为我已经削减了一个源文件,所以不完整

// This will setup a readCallback 
void SocketClass::setupCFCallback() {   
CFSocketContext     context = { 0, this, NULL, NULL, NULL };

if (CFSocketRef macMulticastSocketRef = CFSocketCreateWithNative(NULL, socketHandle_, kCFSocketReadCallBack,readCallBack, &context)) {
    if (CFRunLoopSourceRef macRunLoopSrc = CFSocketCreateRunLoopSource(NULL, macMulticastSocketRef, 0)) {
        if (!CFRunLoopContainsSource(CFRunLoopGetCurrent(), macRunLoopSrc, kCFRunLoopDefaultMode)) {
            CFRunLoopAddSource(CFRunLoopGetCurrent(), macRunLoopSrc, kCFRunLoopDefaultMode);
            macRunLoopSrc_ = macRunLoopSrc;
        }
        else
            CFRelease(macRunLoopSrc);
    }
    else
        CFSocketInvalidate(macMulticastSocketRef);
    CFRelease(macMulticastSocketRef);
}
}



void SocketClass::readCallBack(CFSocketRef inref, CFSocketCallBackType  type,CFDataRef , const void *, void *info) {
if (SocketClass*    socket_ptr = reinterpret_cast<SocketClass*>(info))
    socket_ptr->receive(); // do stuff with your socket

}
//这将设置readCallback
void SocketClass::setupCFCallback(){
CFSocketContext={0,this,NULL,NULL,NULL};
if(CFSocketRef macmulticast socketref=CFSocketCreateWithNative(NULL、socketHandle、kCFSocketReadCallBack、readCallBack和context)){
if(CFRunLoopSourceRef macRunLoopSrc=CFSocketCreateRunLoopSource(NULL,macMulticastSocketRef,0)){
如果(!CFRunLoopContainsSource(CFRunLoopGetCurrent(),macRunLoopSrc,kCFRunLoopDefaultMode)){
CFRunLoopAddSource(CFRunLoopGetCurrent(),macRunLoopSrc,kCFRunLoopDefaultMode);
macRunLoopSrc_u2;=macRunLoopSrc;
}
其他的
CFRelease(macRunLoopSrc);
}
其他的
CFSocketInvalidate(macMulticastSocketRef);
CFRelease(macMulticastSocketRef);
}
}
void SocketClass::readCallBack(CFSocketRef inref、CFSocketCallBackType类型、CFDataRef、const void*、void*信息){
if(SocketClass*socket\u ptr=reinterpret\u cast(信息))
socket_ptr->receive();//用你的socket做一些事情
}

所提供的代码在Mountain Lion 10.8.2上进行了测试。它只需要一个小的修正。 线路
“aio->aio_fildes=sd;”

例如,应更改为:
aio->aio_fildes=open(“/dev/null”,O_RDWR)

以获得预期的结果


参见手册。“aio_write()函数允许调用进程对以前打开的文件执行异步写入。”

您能跟踪它看看有什么问题吗?我使用的SIGIO值(来自sys/signal.h)是#if(!defined(_POSIX_C_SOURCE)| defined(_DARWIN_C_SOURCE))#定义SIGIO 23/*输入/输出可能的信号*/#如果我认为套接字可能不支持的话。我也会尝试使用SIGUSR1。这两个链接回答了这个问题。我尝试过通过fcntl设置O_非块以及O_异步,但也没有帮助。我还必须调查使用F_SETOWN是否有帮助,但我非常确定,OSX上的套接字不支持aio_{read,write}api,这很遗憾。说明:“OSX支持套接字上的异步IO吗?当我调用aio_write()时,我会得到一个ESPIPE错误。同样的代码在Linux中也可以工作,如果我使用文件句柄而不是套接字,它在OSX(10.5.7)中也可以工作。”。似乎Mac上的sockets+aio需要额外的步骤,或者我只是想做一些还不受支持的事情。非常感谢您的帮助。”回复:“OS X支持sockets上的异步IO吗?不。”从技术上讲,POSIX aio提供了处理各种完成通知方法的标准方法。当然,Linux并没有很好地实现该API。