iOS アプリケーションのバックグラウンドで多くのことを実行したいが、スレッドを作成して (たとえば GCD を使用して) このバックグラウンド アクティビティを実行するように適切にコーディングしたとします。
ある時点で変数の更新を書き込む必要があるが、この更新が発生する可能性がある場合、または作成したスレッドのいずれかが発生する場合はどうでしょう。
明らかにその変数を保護したいので、キーワード@synchronized
を使用してロックを作成できますが、ここに問題があります (Apple のドキュメントからの抜粋)。
ディレクティブは
@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 つのスレッドだけが、両方が完了するまでブロックする必要があるというのは論理的に思えます (そして、これは明らかに同期を使用するときに最初に考えたことでした)。
ただし、実際の状況でテストしたところ、そうではないようで、メイン スレッドもロックに悩まされているようです。
UI がブロックされないように、このメカニズムを使用して別のスレッドにログを記録します。しかし、集中的にログを記録すると、UI (メイン スレッド) は明らかに大きな影響を受けます (スクロールはそれほどスムーズではありません)。
したがって、ここで 2 つのオプションがあります。バックグラウンド タスクが重すぎてメイン スレッドにさえ影響を与えるか (これは疑問です)、ロック操作の実行中に同期もメイン スレッドをブロックします (これについては再検討を始めています)。
Time Profiler を使用して、もう少し掘り下げます。