C++ OSX与Linux上的AIO-为什么它不';不能在Mac OS X 10.6上工作
我的问题很简单。为什么下面的代码可以在Linux上运行,而不能在Mac OS X 10.6.2 Snow Leopard上运行 要编译,请将文件保存到aio.cc,并在Linux上使用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,这意味着“
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。