2012-04-24 9 views
2

iOSアプリケーションのバックグラウンドで多くのことをしたいが、スレッドを作成するように正しくコーディングするとしますこのバックグラウンド活動。同期されたキーワードがメインスレッドをブロックしない方法です

ここで、ある時点で変数の更新を書き込む必要がある場合、この更新が発生するか、または作成したスレッドのいずれかが発生する可能性があります。

あなたは明らかにその変数を保護したいとあなたはあなたのためにロックを作成するために、キーワード@synchronizedを使用することができますが、ここでキャッチ(アップルのドキュメントから抜粋)

ある@synchronized()ディレクティブは、コードのセクションをロック単一スレッドで の使用のために。スレッドが 保護されたコードを終了するまで、つまり実行が@synchronized()ブロック内の最後の ステートメントを過ぎて継続するまで、他のスレッドはブロックされます。

だからそれはあなたがオブジェクトを同期して2つのスレッドが同時にそれを書いている場合は、両方のスレッドがそのデータの書き込み完了するまで、でも、メインスレッドがブロックされることを意味します。

このすべてを紹介するコードの例:

// Create the background queue 
dispatch_queue_t queue = dispatch_queue_create("synchronized_example", NULL); 

// Start working in new thread 
dispatch_async(queue,^
       {     
        // Synchronized that shared resource 
        @synchronized(sharedResource_) 
        { 
         // Write things on that resource 
         // If more that one thread access this piece of code: 
         // all threads (even main thread) will block until task is completed. 
         [self writeComplexDataOnLocalFile]; 
        }       
       }); 

// won’t actually go away until queue is empty 
dispatch_release(queue); 

そこで問題は非常に簡単です:これを克服するためにどのように?どのようにして、すべてのスレッドにロックを安全に追加することができますか?その場合、ブロックする必要のないメインスレッドを除きますか?あなたはあなたのいくつかは、コメントとして、それは論理的なようです(これが同期を使用するときに私が最初に考えたもの明らかにした)ロックを取得しようとしている2つだけのスレッドその明確化

FOR

EDIT両方が完了するまでブロックする必要があります。

しかし、実際の状況でテストした場合、これは当てはまりそうもなく、メインスレッドもロックに苦しんでいるようです。

私はこのメカニズムを使用して、UIがブロックされないように物を別々のスレッドに記録します。しかし、私が強烈なロギングを行うと、UI(メインスレッド)は明らかに非常に影響を受けます(スクロールはスムーズではありません)。

バックグラウンドタスクが重すぎてメインスレッドでさえ影響を受ける(疑わしい)、または同期化によってロック操作を実行中にメインスレッドがブロックされる(再考を開始している) 。

私はもう少し時間プロファイラを使用して掘り下げます。

+1

メインスレッドがロックを取得する必要があるのはなぜですか?それはどのように他のどのスレッドとも違うのですか? –

+0

データを書き込むコードが非同期的にキューにディスパッチされるため(dispatch_async) – apouche

+0

これが表示されます。しかし、メインスレッドが同期化されたコードを決して呼び出さない場合、ブロックされません(他のものが言及したように)。あなたはそれをテストしましたか? –

答えて

3

私はあなたがアップルのドキュメントから引用次の文を誤解していると考えています:

スレッドが保護されたコードを終了するまで

他のスレッドがブロックされている

...

これは目を意味するものではありませんすべてのスレッドがブロックされている場合は、同じオブジェクト(例では_sharedResource)で同期しようとしているすべてのスレッドがブロックされているだけです。

次の引用はAppleのThread Programming Guideから引用されています。これにより、同じオブジェクトで同期するスレッドのみがブロックされることが明確になります。

@synchronizedディレクティブに渡されるオブジェクトは、保護されたブロックを区別するために使用される一意の識別子です。前述のメソッドを2つの異なるスレッドで実行し、各スレッドのanObjパラメータに異なるオブジェクトを渡すと、それぞれがロックを取り、別のスレッドによってブロックされずに処理を続行します。ただし、どちらの場合も同じオブジェクトを渡すと、スレッドの1つが最初にロックを取得し、もう1つが最初のスレッドがクリティカルセクションを完了するまでブロックされます。

更新:あなたのバックグラウンドスレッドがあなたのインターフェイスのパフォーマンスに影響を与えているなら、あなたは、バックグラウンドスレッドにいくつかのスリープを置くことを検討する必要があります。これにより、メインスレッドはUIを更新することができます。

GCDを使用していますが、たとえばNSThreadにはスレッドを一時停止する2つの方法があります。 -sleepForTimeInterval:。 GCDではおそらくsleep()に電話することができます。

また、スレッドの優先度を低い優先度に変更することもできます。この場合も、NSThreadsetThreadPriority:です。 GCDでは、ディスパッチされたブロックの優先度の低いキューを使用すると思います。

+0

正直言って私はまったく同じことを考えていましたが、実際の状況ではそうではないようです。私は質問を明確にするため編集しました。 – apouche

+1

更新に関して、メインスレッドはブロックしていませんが、CPUリソースを他のスレッドと共有する必要があります。バックグラウンドスレッドが大量の作業を行っている場合、これはUI更新に影響する可能性があります。 – mttrb

+0

確かに、Time Profilerは、メインスレッドで何も重くはなかったが、キューはCPU側ですべてのトラフィックを駆動していることを示しました。あなたの助けをもう一度ありがとう – apouche

3

私があなたを正しく理解しているかどうかはわかりませんが、@synchronizeはすべてのスレッドをブロックするのではなく、ブロック内のコードを実行したいスレッドだけをブロックします。おそらく解決策はあります。メインスレッドでコードを実行しないでください。

あなたは、単にメインスレッドがロックを獲得することを避けるためにしたい場合は、この(と難破船の大混乱を)行うことができます。

dispatch_async(queue,^
       {    
        if(![NSThread isMainThread]) 
        { 
         // Synchronized that shared resource 
         @synchronized(sharedResource_) 
         { 
          // Write things on that resource 
          // If more that one thread access this piece of code: 
          // all threads (even main thread) will block until task is completed. 
          [self writeComplexDataOnLocalFile]; 
         }   
        } 
        else 
         [self writeComplexDataOnLocalFile];    
       }); 
+0

ありがとう、しかし、私はブロックの部分がメインスレッドで決して呼び出されないので、それは私の問題をかなり解決します。私は明確化のために私の質問を編集しました。 – apouche

関連する問題