2011-12-21 22 views
14

私はタイマーとストリームを添付するNSRunLoopオブジェクトを持っています。それは素晴らしい作品です。それを止めることは別の話です。CFRunLoopRun()vs [NSRunLoop run]

[runLoop run]を使用してループを実行します。

CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop])を使用してループを停止しようとすると、ループは停止しません。代わりにCRunLoopRun()を使用してループを開始すると、動作します。また、私のカスタム実行ループを実行しているスレッドで正しい呼び出しが行われていることを確認しました。私はpthread_self()でこれをデバッグしました。

私はメーリングリストのアーカイブを見つけました。開発者は「実行メソッドNSRunLoopを使用してループを開始した場合、CRunLoopStop()を使用してください」と言っていました。なぜそれがそれであるのか理解できます。通常は、同じ関数セットからイニシャライザとファイナライザをペアにします。

NSRunLoopを「CFに頼らずに」停止するにはどうすればよいですか? NSRunLoopにはstopメソッドが表示されません。すべての入力ソースを削除CFRunLoopStop()

  • の使用を停止するために実行ループを知らせるタイムアウト値
  • で実行する実行ループ

    1. 設定、しかし:ドキュメントは、次の3つの方法で実行ループを停止することができますことを言いますあなたの背中の後ろに実行ループまあ

    に何を立ち往生かを知ることはできませんので、これは私はすでに2を試してみましたが、あなたので、それを感じる「醜い」があります、実行ループを停止する信頼性の低い方法です。 CFを掘り起こす必要があります。 3.質問から外れています - 私は非決定論的なコードを好きではありません。

    これは私に1を残します。ドキュメントを正しく理解していれば、既存の実行ループにタイムアウトを「追加」することはできません。新しい実行ループはタイムアウトでのみ実行できます。新しい実行ループを実行すると、ネストされた実行ループのみが作成されるため、問題は解決しません。私はまだ古いものに直ちにポップアップするでしょう、私は停止したいのと同じ...そうですか?私はこのことを誤解しているかもしれません。また、私はタイムアウト値でループを実行したくありません。私がするならば、CPUサイクルの焼き付け(低タイムアウト値)と応答性(高タイムアウト値)の間でトレードオフをしなければならないでしょう。

    これは私が(擬似コードっぽい)今持っている設定です。

    Communicator.h

    @interface Communicator : NSObject { 
        NSThread* commThread; 
    } 
    
    -(void) start; 
    -(void) stop; 
    @end 
    

    Communicator.m

    私は何
    @interface Communicator (private) 
    -(void) threadLoop:(id) argument; 
    -(void) stopThread; 
    @end 
    
    @implementation Communicator 
    -(void) start { 
        thread = [[NSThread alloc] initWithTarget:self 
                selector:@selector(threadLoop:) 
                 object:nil]; 
        [thread start]; 
    } 
    
    -(void) stop { 
        [self performSelector:@selector(stopThread) 
           onThread:thread 
           withObject:self 
          waitUntilDone:NO]; 
        // Code ommitted for waiting for the thread to exit... 
        [thread release]; 
        thread = nil; 
    } 
    @end 
    
    @implementation Communicator (private) 
    -(void) stopThread { 
        CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]); 
    } 
    
    -(void) threadLoop:(id) argument { 
        // Code ommitted for setting up auto release pool 
    
        NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 
    
        // Code omitted for adding input sources to the run loop 
    
        CFRunLoopRun(); 
        // [runLoop run]; <- not stoppable with 
    
        // Code omitted for draining auto release pools 
    
        // Code omitted for signalling that the thread has exited 
    } 
    @endif 
    

    何をする?それは一般的な/ CFで混乱する良いパターンですか?私は十分に財団を知らない。 CF層に干渉するのはおそらく危険です(メモリ破壊、不整合、メモリリークに関して)?私が達成しようとしているものを達成するための良いパターンがありますか?

  • 答えて

    7

    あなたはうまくいきます。 Foundationで目標を達成できない場合、CoreFoundationを使用するのに問題はありません。 CoreFoundationはC言語であるため、メモリ管理に混乱するのは簡単ですが、NSRunLoopsometimes it may even be saferCFRunLoop APIはスレッドセーフで、NSRunLoopはそうではありません)ではなく、CFRunLoopを使用することに本質的な危険はありません。

    NSRunLoopを停止する場合は、runMode:beforeDate:を使用して実行できます。 runMode:beforeDate:は、入力ソースが処理されるとすぐに戻り、タイムアウト日に達するまで待つ必要はありません。

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
    NSDate *date = [NSDate distantFuture]; 
    while (!runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date]); 
    

    はその後、実行ループを停止するには、あなただけのYESrunLoopIsStoppedを設定する必要があります。

    +0

    ああ、賢い!私は 'runMode'が一度だけ走っているのを見ていませんでした。実行ループを何度も繰り返して起動すると、大きなパフォーマンス上のペナルティが発生しますか? –

    +0

    いいえ、そこにはありません:それは ' - [NSRunLoop run]'と ' - [NSRunLoop runUntilDate:]'がどのように動作するかです。 –

    +1

    runLoopIsStoppedをYESに設定するだけでスレッドは停止しません。 YESに設定し、そのrunloopのスレッドでアクションを実行する必要があります。そうしないと、[runLoop runMode:NSDefaultRunLoopMode beforeDate:date]は終了しません。 これは私が理解する年齢がかかりました。 – Pada