4

私の質問は本当に簡単です。以下のコードがLinuxで機能し、Mac OS X 10.6.2SnowLeopardでは機能しない理由。

コンパイルするには、ファイルをaio.ccに保存し、g++ aio.cc -o aio -lrtLinuxおよびMacOSXでコンパイルしますg++ aio.cc -o aio。MacでのテストにはMacOSX 10.6.2を使用し、LinuxでのテストにはLinuxカーネル2.6を使用しています。

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);  
}

更新(2010年2月):OSXはソケットでAIOをまったくサポートしていません。バマー!

4

4 に答える 4

2

The presented code was tested on Mountain Lion 10.8.2. It works with a small correction. The line
"aio->aio_fildes = sd;"

should be changed for example to:
aio->aio_fildes = open( "/dev/null", O_RDWR);

to get the expected result.

see manual. "The aio_write() function allows the calling process to perform an asynchronous write to a previously opened file."

于 2013-01-28T03:53:24.233 に答える
1

10.6.2 のコードと非常によく似たコード (ファイルへの書き込み) は問題なく動作するので、あなたがしようとしていることが可能です。

好奇心から、SIGIO 定数にどのような値を使用していますか? OS X で無効な値を使用すると、aio_write が失敗することがわかったので、常に SIGUSR1 を渡します。

sigaction() の戻り値をチェックして、シグナルの詳細を確認してみてはいかがでしょうか。

于 2010-02-17T22:59:42.727 に答える
1

OSX (CF)RunLoop 経由でソケットを使用できるようにします。または、ランループからコールバックを取得します。これは、Mac で async IO を使用するために私が見つけた最もエレガントな方法です。既存のソケットを使用して、CFSocketCreateWithNative を実行できます。そして、ランループにコールバックを登録します。

これは、ソースファイルを削減したため、不完全なセットアップ方法を示すコードの小さなスニペットです...

// 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

}
于 2011-02-25T16:06:17.757 に答える
1

リンクで提起されたポイントはすべて、io 完了通知を生成するための別の方法 (BSD 固有のメカニズムである kqueue など) を指していますが、非同期 io の POSIX メソッドに関する質問には実際には答えていません。ダーウィンに取り組んでいるかどうか。

UNIX の世界は、実際にはこのための解決策の寄せ集めであり、すべてのプラットフォームで機能する試行錯誤された解決策が 1 つあれば、それは本当に良いことです。

これは暗黒面での刺し傷ですが、SIGUSR1 を使用するだけでなく、ソケット ハンドルにノンブロッキングを設定する (つまり、ソケット オプション O_NONBLOCK を設定する) ことも役立つ場合があります。

時間があれば、あなたのソケット サンプルを使用して、それから何かを得ることができるかどうかを確認します。

幸運を祈ります。

于 2010-02-18T21:50:16.893 に答える