2010-02-06 164 views
3

我的问题非常简单。为什么下面的代码可以在linux上工作,而不是在Mac OS X上。OS X上的AIO与Linux - 为什么它不能在Mac OS X上运行

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

我在OS X上看到的故障是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); 
} 

UPDATE:OSX根本不会对插座suppport AIO。坏消息!

+0

什么是aio?链接? – dmckee 2010-02-06 04:10:08

+0

你能跟踪它看看有什么问题吗? – ggiroux 2010-02-06 05:56:31

回答

1

我的代码非常类似于你的10.6.2(但是写入文件)工作没有任何问题 - 所以有可能做你正在尝试的。

出于好奇,您对SIGIO常数有什么价值? 我发现这里在OS X中的一个无效值会导致aio_write失败 - 所以我总是通过SIGUSR1。

也许检查sigaction()的返回值来验证信号细节?

+0

我使用(从SYS/signal.h中)的SIGIO值是 的#if(!定义(_POSIX_C_SOURCE)||定义(_DARWIN_C_SOURCE)) 的#define SIGIO 23/*输入/输出的可能信号*/ #ENDIF 我认为它可能不支持套接字。尽管我也会尝试使用SIGUSR1。 – invalidopcode 2010-02-18 03:37:36

+0

这两个链接回答了这个问题。 http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.html http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html – invalidopcode 2010-02-18 04:29:15

1

链接中提出的要点都指向提升io完成通知的不同方法(例如,kqueue是BSD特定的机制),但并未真正回答您关于异步io的POSIX方法的问题。以及他们是否在达尔文工作。

UNIX世界真的是一个很好的解决方案,如果有一个可以跨所有平台使用的经过验证的解决方案,唉,目前还没有 - POSIX是一个针对最一致的。

这一点在黑暗中刺,但它可能是有用的,以及设置非阻塞您套接字句柄(即集套接字选项O_NONBLOCK)以及使用SIGUSR1

如果我得到了一段时间我我会和你的套接字样本一起工作,看看我能不能从中得到任何东西。

祝你好运。

+0

我试过了通过fcntl设置O_NONBLOCK以及O_ASYNC,但它也没有帮助。 我也必须调查是否使用F_SETOWN帮助,但我很确定aio_ {读取,写入} api不支持OS X上的套接字,这很难以诚实。 – invalidopcode 2010-02-19 08:23:42

+0

http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00016.html说: 上的插座“是否OS X支持异步IO 当我打电话aio_write()我得到一个错误ESPIPE?相同的代码可以在Linux中使用,如果我使用文件句柄而不是套接字,它也可以在OS X(10.5.7)中使用。似乎Mac上的套接字+ aio需要额外的步骤,我只是试图做一些不支持的东西。 任何帮助,非常感谢。“ 的http://lists.apple.com/archives/Macnetworkprog/2009/Aug/msg00017.html回复: “?上的插座是否OS X支持异步IO 号” – invalidopcode 2010-02-19 08:26:49

+0

从技术上讲,POSIX AIO提供了处理各种完成通知方法的标准方法。当然,Linux并没有很好地实现这个API。 – 2010-07-27 02:08:52

1

OSX允许您通过(CF)RunLoop使用套接字。或者从runloop获得回调。 这是我发现在Mac上使用异步IO的最优雅的方式。 您可以使用您现有的套接字并执行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 

} 
1

所提出的代码在山狮10.8.2测试。它适用于一个小的更正。该行
“aio-> aio_fildes = sd;”

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

以获得预期结果。

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