3

私は現在CFReadStreamHasBytesAvailableで新しいデータのポーリング私CFReadStreamです。CFReadStreamHasBytesAvailableポーリング - ベストプラクティス

(まず、いくつかの背景:私は私自身のスレッドをやっていると私は実行ループのものを台無しに/必要性を望んでいないので、クライアントコールバックのものは本当にここには適用されません)。

私の質問は次のとおりです。ポーリングの受け入れ方法は何ですか?

Apple's documentationはあまり役に立ちません。

「お待ちください」とお勧めします。

while(!done) 
{ 
    if(CFReadStreamHasBytesAvailable(readStream)) 
    { 
    CFReadStreamRead(...) ... bla bla bla 
    } else { 
    usleep(3600); // I made this up 
    sched_yield(); // also made this up 
    continue; 
    } 
} 

usleepsched_yield「十分に良い」:私は現在ただの線に沿って何かをやっていますか?そこにはusleepで寝るための「良い」番号がありますか?

(これは私自身のスレッドで実行されているので、私はCFReadStreamReadでブロックすることができます - これは素晴らしいですが、アップロードの進捗状況とダウンロードの進捗状況にも悩まされていますので、助けてください...)。

すべての洞察が高く評価されます - ありがとう!

+0

アップロードとダウンロードのスレッドは別ですか? – frankodwyer

+0

各リクエストには効果的に独自のスレッドがあります。 – atebits

+0

多分私が理解していないいくつかの要件がありますが、アップロードとダウンロードが自分のスレッドに割り当てられている場合、問題は解決しますか?つまり、ストリームを1つのスレッドに読み込ませ、ストリームに1つのスレッドを書き込み、ブロックします。ただし、それらを同期させる必要があります。 – frankodwyer

答えて

4

私はあなたがベストプラクティスは、本質的にベストプラクティスではありません何かをするためのもので何を求めているので、この質問はパラドックスのビットだと思う;)

完璧な方法は、私は、ネットワーク上のブロッキングのためにあります場合には/ O、代わりにポーリングを引き起こす任意の妥協は、定義上、ベストプラクティスではありません。あなたが投票を行う場合、私は代わりに何でもPOSIXの睡眠やあなたが想像している利回り法を使用しての、あなたのスレッド上で、「日まで実行ループを実行」する方が適切かもしれないと思う、と述べ

。各スレッドは独自のrunloopを取得することを忘れないでください。基本的にrunloopを実行することで、Appleは将来の日付までブロックするためのベストプラクティスの概念を採用することができます。

時間の遅れに関しては、楽しい時代のための決定的な答えが得られるかどうかはわかりません。これは、I/Oがネットワークから読み込まれる準備ができている間に、ポーリングサイクルとCPUの間を行き来することと、実行ループに詰まったこととの間のトレードオフです。

理想的には、I/Oブロッキングコールを使用してこの作業を行うように努力していますが、&アイドルテクニックのポーリングを使用する場合は、特定の遅延時間についてあまり気をつけないでください。うまくいくものを選んで、どちらの方向にもパフォーマンスに負の影響を与えないように見えるだけです。

(ポーリングとブロッキングのことについてあまりにも宗教的ではないことを明確にしたいと思います。私は、明らかに昇格されたソリューションを探しているので、その価値を強調しています)。

+0

あなたは確かに間違っていない:)。私はプレーンなオールスレッドを使用していますが、ランロップは関連付けられていません。私はrunloopのオーバーヘッドを避けると思った(無視できる?)。私はまた、ポーリングがシステムのあるレベルで起こると考えていたので、私は自分自身でそれを行うかもしれません - 私はそれについて間違っているかもしれませんが。 – atebits

+0

私はあなたがシステムのいくつかの恋人でポーリングが起こるという仮定について間違っていると思います。 runloopベースのCFStreamの仕組みは、ネットワークI/Oが実際に待機している時点で、文字通りハードウェア駆動ウェイクアップになります。だから、待っているだけのポーリングはありません。 – danielpunkass

+0

うん、そうだよ。私はこれを行う最善の方法は、runloopを使用して定期的にアップロードの状態を確認するためのタイマーをスケジュールすることです。 (または、CFRunLoopRunInModeを使用して、runloopにコントロールを定期的に返すようにする - オーバーヘッドの違い?)。 – atebits

1

別のスレッド(帯域幅の監視とスロットルなどのカスタム作業用)で手動CFStreamベースの接続を行う場合は、CFReadStreamScheduleWithRunLoop、CFRunLoopRunInModeおよびCFReadStreamSetClientの組み合わせを使用します。基本的には0.25秒間実行した後、ストリームの状態を確認します。クライアントのコールバックも、それ自体で通知されます。これにより、私は定期的に読み込み状態をチェックし、いくつかのカスタム動作を行いますが、主に(ストリーム)イベントに依存しています。

static const CFOptionFlags kMyNetworkEvents = 
kCFStreamEventOpenCompleted 
| kCFStreamEventHasBytesAvailable 
| kCFStreamEventEndEncountered 
| kCFStreamEventErrorOccurred; 

static void MyStreamCallBack(CFReadStreamRef readStream, CFStreamEventType type, void *clientCallBackInfo) { 
    [(id)clientCallBackInfo _handleNetworkEvent:type]; 
} 


- (void)connect { 
    ... 

    CFStreamClientContext streamContext = {0, self, NULL, NULL, NULL}; 
    BOOL success = CFReadStreamSetClient(readStream_, kMyNetworkEvents, MyStreamCallBack, &streamContext); 


    CFReadStreamScheduleWithRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 

    if (!CFReadStreamOpen(readStream_)) { 
    // Notify error 
    } 

    while(!cancelled_ && !finished_) { 

    SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, NO); 

    if (result == kCFRunLoopRunStopped || result == kCFRunLoopRunFinished) { 
     break; 
    } 

    if (([NSDate timeIntervalSinceReferenceDate] - lastRead_) > MyConnectionTimeout) { 
     // Call timed out 
     break; 
    } 

    // Also handle stream status CFStreamStatus status = CFReadStreamGetStatus(readStream_); 
    if (![self _handleStreamStatus:status]) break; 
    } 

    CFRunLoopStop(CFRunLoopGetCurrent()); 


    CFReadStreamSetClient(readStream_, 0, NULL, NULL); 
    CFReadStreamUnscheduleFromRunLoop(readStream_, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 

    CFReadStreamClose(readStream_);  

} 


- (void)_handleNetworkEvent:(CFStreamEventType)type { 
    switch(type) { 
     case kCFStreamEventOpenCompleted: 
      // Notify connected 
      break; 

     case kCFStreamEventHasBytesAvailable: 
      [self _handleBytes]; 
      break; 

     case kCFStreamEventErrorOccurred: 
      [self _handleError]; 
      break; 

     case kCFStreamEventEndEncountered: 
      [self _handleBytes]; 
      [self _handleEnd]; 
      break; 

     default: 
      Debug(@"Received unexpected CFStream event (%d)", type); 
      break; 
    } 
} 
+0

runloopsの目的に対して、イベントの場合は、あなたに通知するはずですよね? – elsurudo

関連する問題