2009-07-18 12 views
8

私は、私が合理的に知的な人だと思っていました。
リンゴの「スレッドプログラミングガイド」は、自己欺瞞を維持する私の自我を粉砕しました。Objective-Cを実行してメソッドを停止して再起動しますか?

私は、以下の例では二次スレッドで繰り返し実行したいメソッドがあります。
このメソッドの繰り返し呼び出しを繰り返して開始できるようにしたいと考えています。

コードがスレッドを開始します。
ブール値stuffToDoがtrueの場合、
それはdoStuffを呼び出します。
そう
それは少し休息を持っています。
それは私がそれを止めるように言うまで再びループします

私は現在のコードは何もしないときに 'stuffToDo'をチェックし続けるので、無駄に思えます。

私はstuffToDoを取り除き、必要に応じてスレッドをスポーンして取り消すことができます。
これはまた無駄に思えます。すでに実行しているスレッドが誤って新しいスレッドを生成しないように注意する必要があります。

私は答えは効率的に私の苦境を解決するために、Appleの「スレッドプログラミングガイド」の「実行ループの管理」セクションのどこかに見つけることができると確信しているが
は、おそらくそれは、カスタム入力ソース

を必要とするしかし、私は本当に午前この文書が挑戦的であることを発見した
この文書が私の脳の中にあまりにも多くのスレッドを生成し、計算が停止するようです。

enum eRenderThreadMode 
{ 
    render_not_started, 
    render_run, 
    render_cancel, 
    render_finished 
}; 


- (IBAction) startThread:(id)sender 
{ 
    self.renderThreadMode = render_run; 
    label.text = @"doing stuff"; 
    [NSThread detachNewThreadSelector:@selector(keepDoingStuff) toTarget:self withObject:nil]; 

} 

- (void)keepDoingStuff 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    while (renderThreadMode == render_run) 
    { 
     if(stuffToDo) 
     { 
      [self doStuff]; 
     } 
     else 
     { 
      [NSThread sleepForTimeInterval:kLittleRest]; 
     } 
    } 
    self.renderThreadMode = render_finished; 
    [pool release]; 
} 


- (IBAction)stopThread:(id)sender 
{ 
    self.renderThreadMode = render_stop; 

    while (self.renderThreadMode == render_cancel) 
    { 
     [NSThread sleepForTimeInterval:kLittleRest]; 
    } 
} 

答えて

7

セカンダリスレッドがスリープしている同期オブジェクトを使用できます。 This Apple pageには、あなたが望むことができる「条件」という機能があることを示しています。条件または同様の同期オブジェクトを使用すると、実行する作業があるとき(スレッドが終了するとき)にのみスレッドが起動されます。

+0

NSConditionLockを使用してください。これは標準的なスレッド構造です。 –

+0

ありがとう、これは私が欲しいものを正確に行うように見える –

+0

NSConditionLockではなく、提案されているようにNSConditionを使用しました。 Conditionではなく、実際にConditionLockを意味しましたか? もしそうなら、NSConditionLockを使ってこれを実装するとどう思いますか? 以前は、目的のCスレッドで作業していませんでしたが、さまざまなアプローチについて聞きたいと思っています。 –

7

ええ、あなたはrunloopを使いたいと思っています。欠けているものは、これをすべて設定する方法です。あなたの投稿を修正し、何が起こっているのかを説明します。それはあなたを脅かす場合は、この時点で、あなたは上記のコードを見て、「まあ、ということを考えるべきであるので、それはトリッキーで、あなただけの経験

- (IBAction) startThread:(id)sender 
{ 
    self.renderThreadMode = render_run; 
    label.text = @"doing stuff"; 
    self.backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(keepDoingStuff) object:nil]; 
    [self.backgroundThread start];  
} 

//Okay, this is where we start changing stuff 
- (void)keepDoingStuff 
{ 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

     //A runloop with no sources returns immediately from runMode:beforeDate: 
     //That will wake up the loop and chew CPU. Add a dummy source to prevent 
     //it. 

     NSRunLoop *runLopp = [NSRunLoop currentRunLoop]; 

     NSMachPort *dummyPort = [[NSMachPort alloc] init]; 
     [runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode]; 
     [dummyPort release]; 
     [pool release]; 

     while (1) 
     { 
       NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; 
       [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
       [loopPool drain]; 
     } 
} 

オーケーから学ぶいくつかの落とし穴がありますが、心配しないでくださいこれは本当のことですが、実行中のrunloopがあるので、それに基づいてrunloopを実行できます。performSelector:onThread:withObject:waitUntilDone:

- (void) doStuffOnBackgroundThread 
{ 
    [self performSelector:@selector(doStff) onThread:self.backgroundThread withObject:nil waitUntilDone:NO]; 
} 

メインスレッド(または他のスレッド)で上記のメソッドを呼び出すと、さまざまな引数をマーシャリングし、特定のrunloopをエンキューします必要に応じて目を覚ます。この場合、self.backgroundThreadはrunMode:beforeDate:から起床し、-doStuffを実行し、ループを終了し、runMode:beforeDate:で待機してスリープ状態に戻ります。スレッドを分解できるようにしたい場合は、コード内にあるようにwhileループ内に変数を設定することができますが、スリープ状態になるとスレッドが消えてしまうのを覚えていますが、これはperformSelector:onThread:withObject:waitUntilDone:を介して制御変数を設定するメソッドで、これはプラス記号として、変数がバックグラウンドスレッドからのみ設定され、同期の問題を単純化することを意味します。

さて、私はあなたの問題を解決すると思うので、義務的なプラグを作る時間:スレッドでこれをやりたいのですか? NSOperationとNSOperationQueueは、処理するために時々いくつかのデータをエンキューする必要がある場合に、すべてのスレッド問題を処理する非常に簡単なソリューションです。彼らは、仕事をスケジュールし、依存関係を管理し、スレッドを構築/解体するだけでなく、すべてのランブルウェイク/スリープを世話します。

+0

すばらしい詳細な回答に感謝します。 Inは、NSOperationを使用していませんでした。なぜなら、NSOperationは有限の作業量を処理するように設計されているからです。スレッドを開始し、無期限に実行したい(最小2秒、最大バッテリは平らになっていますか?) NSOperation上でスレッドを使用する必要があるかどうかはわかりませんが、曖昧な感覚に基づいており、調べる価値が最も高いと感じました –

+0

どちらかを実行できます。 NSOperationQueueは空になるまで実行を続けますが、いつでもNSOperationをスローしてNSOperationをスローすることができます。 –

+0

おかげでルイ、 上記の2つの質問、runLoopはどこから来たのですか? スレッドが動作しているときにもdoStuffを呼び出すようにしたい:私の介入なしでできるだけ早く呼び出すように構造体を変更するかもしれないので、私はdoCommandSelector: onThread:self.backgroundThread withObject:nil waitUntilDone:NO]; –

関連する問題