2009-05-19 9 views
19

のためのきちんとしたコードは、ウェブ上で最も文書化されものではありません、良い例の一握りがあります。非同期IO(選択/世論調査/ファイルディスクリプタ/ kqueueのなどと非ブロック記述子)しながら、非同期IO

はしかし、すべてのこれらの例は、呼び出しによって返されたハンドルを決定した、単に「do_some_io(fd)」スタブを持っています。このような方法で実際の非同期IOに最適な方法を実際に説明するものではありません。 IOをブロック

は、コードを読むことは非常に整頓して簡単です。非ブロッキング、非同期IOは、一方で、毛深く、乱雑です。

どのようなアプローチがありますか?堅牢で読みやすいものは何ですか? GCCの計算GOTOSを用い

void do_some_io(int fd) { 
    switch(state) { 
    case STEP1: 
     ... async calls 
     if(io_would_block) 
      return; 
     state = STEP2; 
    case STEP2: 
     ... more async calls 
     if(io_would_block) 
      return; 
     state = STEP3; 
    case STEP3: 
     ... 
    } 
} 

又はおそらく(AB):

#define concatentate(x,y) x##y 
#define async_read_xx(var,bytes,line)  \ 
    concatentate(jmp,line):     \ 
    if(!do_async_read(bytes,&var)) {   \ 
     schedule(EPOLLIN);     \ 
     jmp_read = &&concatentate(jmp,line); \ 
     return;        \ 
} 

// macros for making async code read like sync code 
#define async_read(var,bytes) \ 
    async_read_xx(var,bytes,__LINE__) 

#define async_resume()   \ 
    if(jmp_read) {    \ 
     void* target = jmp_read; \ 
     jmp_read = NULL;   \ 
     goto *target;   \ 
    } 

void do_some_io() { 
    async_resume(); 
    async_read(something,sizeof(something)); 
    async_read(something_else,sizeof(something_else)); 
} 

それともC++例外と状態機械、作業者の機能が中断/再開ビットをトリガすることができ、または、おそらくテーブル駆動状態機械?

その方法ではなく、それを動作させるために、その方法には、保守私が追いかけてることを確認するために!

答えて

16

私は、http://www.kegel.com/c10k.htmlを見てみることをお勧めします.2番目はlibeventのような既存のライブラリ、Boost.Asioで既に仕事をしていて、どのように動作するかを見てみましょう。

  • 選択が単純な反応器エッジまたはレベルの両方がIOCPである
  • 異なるアプローチを必要とするインタフェースを引き起こした
  • ファイルディスクリプタ:

    点アプローチは、システムコールのタイプごとに異なっていてもよいということですproactorは、他のアプローチが必要

提案:C++またはC

ためlibeventためBoost.Asioような良い既存のライブラリを使用します

EDIT:これはASIOはproactorとして動作するので、操作が完了し、 が内部EWOULDBLOCKを処理するとき、それはあなたを通知ASIOこの

class connection { 
    boost::asio:ip::tcp::socket socket_; 
public: 
    void run() 
    { 
     // for variable length chunks 
     async_read_until(socket_,resizable_buffer,'\n', 
       boost::bind(&run::on_line_recieved,this,errorplacehplder); 
     // or constant length chunks 
     async_read(socket_,buffer(some_buf,buf_size), 
       boost::bind(&run::on_line_recieved,this,errorplacehplder); 
    } 
    void on_line_recieved(error e) 
    { 
     // handle it 
     run(); 
    } 

}; 

をどのように処理するかです。

反応器として使用すると、この動作をシミュレートすることができるあなたは単語の場合:そのような

class conn { 
    // Application logic 

    void run() { 
     read_chunk(&conn::on_chunk_read,size); 
    } 
    void on_chunk_read() { 
     /* do something;*/ 
    } 

    // Proactor wrappers 

    void read_chunk(void (conn::*callback),int size, int start_point=0) { 
     read(socket,buffer+start,size) 
     if(complete) 
      (this->*callback() 
     else { 
      this -> tmp_size-=size-read; 
      this -> tmp_start=start+read; 
      this -> tmp_callback=callback 
      your_event_library_register_op_on_readable(callback,socket,this); 
     } 
    } 
    void callback() 
    { 
     read_chunk(tmp_callback,tmp_size,tmp_start); 
    } 
} 

は何か。

+0

libeventもハイとローウォーターマークで、イベントラッパーをバッファリングされている例を見てみたい便利 – Will

+0

EDITED:例を追加しました – Artyom

+0

Artyomに感謝します。 – Will

5

ステートマシンは、1つのすてきなアプローチです。それは、将来の頭痛を救うための複雑さを少し前にしています。未来は本当にすぐに始まります。 ;-)

もう一つの方法は、スレッドを使用することで、各スレッドで単一のFDにI/Oをブロックします。ここでのトレードオフは、I/Oを単純にすることですが、は同期の複雑さを導入する可能性があります。

+11

非同期のためのステートマシンの簡単な例ioは私があまりにも – Will

+0

だろうぎりぎりのIO処理を避ける便利な方法です。再開可能でなければならないコードを呼び出すコードで、この状態をどのように表現しますか? – Viet

0

"io"と処理を切り離したい場合は、読み込んだコードが非常に読みやすくなります。基本的にはあります。そして、実際のコードは、プロセスのイベントであり、そしてあなたが複数の要求応答を持っている場合でも、それはかなり読みやすいです


    int read_io_event(...) { /* triggers when we get a read event from epoll/poll/whatever */ 

    /* read data from "fd" into a vstr/buffer/whatever */ 

    if (/* read failed */) /* return failure code to event callback */ ; 

    if (/* "message" received */) return process_io_event(); 

    if (/* we've read "too much" */) /* return failure code to event callback */ ; 

    return /* keep going code for event callback */ ; 
    } 


    int process_io_event(...) { 
     /* this is where you process the HTTP request/whatever */ 
    } 

...、あなただけの「)(read_io_eventを返す」か状態または何を設定した後、 。

+2

バッファを構築するには、回線またはメッセージレベルで十分に機能します。もっと複雑なものを解析しているときは、process_io_event()ハンドラでこの状態をどのように表現するのですか? – Will

3

この問題を解決するための優れたデザインパターン「コルーチン」が存在します。

これは、シンクロナイゼーションフローとまったく同じような整然としたコードと、コンテキストの切り替えなしの優れたパフォーマンス(async ioのように)の両方の点で最高です。コルーチンは、単一の命令ポインタを持つ、普通の同期スレッドのように見えます。しかし、多くのコルーチンは、1つのOSスレッド内で実行できます(いわゆる "協調マルチタスク")。

例コルーチンコード:

void do_some_io() { 
    blocking_read(something,sizeof(something)); 
    blocking_read(something_else,sizeof(something_else)); 
    blocking_write(something,sizeof(something)); 
} 

が同期コードのように見えるが、実際には、制御フローは次のように、別の方法を使用します。

void do_some_io() { 
    // return control to network io scheduler, to handle another coroutine 
    blocking_read(something,sizeof(something)); 
    // when "something" is read, scheduler fill given buffer and resume this coroutine 

    // return control to network io scheduler, to handle another coroutine 
    CoroSleep(1000); 
    // scheduler create async timer and when it fires, scheduler pass control to this coroutine 
    ... 
    // and so on 

だから、シングルスレッドスケジューラコントロールのユーザー定義を持つ多くのコルーチンコードとioへの整然とした同期的な呼び出し。

C++コルーチンの実装例では、「boost.coroutine」ブーストの(実際には一部ではありません:) http://www.crystalclearsoftware.com/soc/coroutine/ このライブラリは、完全にコルーチン仕組みを実装し、スケジューラと非同期IO層としてboost.asio使用することができます。

+0

[Boost.Coroutine](http://www.boost.org/doc/libs/release/libs/coroutine/doc/html/index.html)は現在、追加の一部です。 – Mankarse

1

async_schedule()、async_foreach()、async_tick()などを提供するメインループが必要です。これらの関数は、次にasync_tick()を呼び出したときに実行されるメソッドのグローバルリストに入ります。その後、はるかにきちんとしたコードを書くことができ、switch文も含まれません。あなただけ書くことができ

async_schedule(callback, arg, timeout); 

または:

async_wait(condition, callback, arg, timeout); 

を次に、あなたの条件にも(その変数にアクセスするときは、スレッドの安全性の世話をすることを提供する)別のスレッドで設定することができます。

非プリエンプティブなマルチタスキングを望んでいたため、埋め込みプロジェクト用にCで非同期フレームワークを実装しました。メインループの繰り返しごとに少しでも作業をして多くのタスクを実行するのに最適です。

コードはここにある:https://github.com/mkschreder/fortmax-blocks/blob/master/common/kernel/async.c

+1

リンクは機能しなくなりました。 –

関連する問題