オブジェクトを作成したスレッド上で明示的にアクセスしない場合、自分のスレッドの外で作成したオブジェクトを操作しても安全ですか?

StackOverflow https://stackoverflow.com/questions/67154

質問

私は Cocoa ソフトウェアに取り組んでいますが、大規模なデータ (コア データ) のインポート中に GUI の応答性を維持するには、メイン スレッドの外側でインポートを実行する必要があります。

ロックを使用せずにメインスレッドでオブジェクトを作成した場合でも、それらのオブジェクトに安全にアクセスできますか? もし スレッドの実行中は、これらのオブジェクトに明示的にアクセスしません。

役に立ちましたか?

解決

Core Data では、同じコーディネーターと永続ストアに接続された、インポート スレッドに使用する別の管理オブジェクト コンテキストが必要です。メインスレッドによって使用されるコンテキストで作成されたオブジェクトを別のスレッドにスローして、それらが機能することを期待することはできません。さらに、このために独自のロックを行うことはできません。必要に応じて、オブジェクトが含まれる管理オブジェクト コンテキストを少なくともロックする必要があります。ただし、これらのオブジェクトがコントロールのビューによってバインドされている場合、コンテキストのロックを追加できる「フック」はありません。

無料のランチはありません。

Ben Trumbull は、別のコンテキストを使用する必要がある理由と、「ただ読む」ことが思っているほど簡単でも安全でもない理由のいくつかを次の記事で説明しています。 2004 年後半に webobjects-dev リストに掲載されたこの素晴らしい投稿. 。(スレッド全体は素晴らしいです。) 彼は Enterprise Objects Framework と WebObjects について議論していますが、彼のアドバイスは Core Data にも完全に当てはまります。メッセージの本文の「EC」を「NSManatedObjectContext」に、「EOF」を「Core Data」に置き換えるだけです。

Enterprise Objects Frameworkのように、コアデータのスレッド間でデータを共有する問題の解決策は「Do n't」です。あなたがそれについてさらに考えて、あなたが本当に、正直に、スレッド間でデータを共有する必要がある場合、解決策は、スレッドに分離されたコンテキストに独立したオブジェクトグラフを保持し、1つのコンテキストから保存通知の情報を使用して、他のコンテキスト何を再フェッチするか。 -[NSManagedObjectContext refreshObject:mergeChanges:] は、この用途をサポートするために特別に設計されています。

他のヒント

これはそうだと思います ない CoreData NSManagedObjectContext によって管理される NSManagedObject (またはサブクラス) を安全に操作できます。一般に、CoreData は、管理対象オブジェクトの状態に関して、別のスレッドでそれらのオブジェクトに関連するフォールトを起動するなど、多くの難しいことを実行することがあります。特に、 [NSManagedObject initWithEntity:insertIntoManagedObjectContext:] (OS X 10.5 の NSManagedObjects に指定されたイニシャライザ) は、返されたオブジェクトが他のスレッドに安全に渡せるかどうかを保証しません。

複数のスレッドでの CoreData の使用については、Apple のドキュメントで詳しく説明されています。 開発サイト.

ロックを使用する最大のポイントは、2 つのスレッドが同じリソースにアクセスしようとしないようにすることです。他のメカニズムを通じてそれを保証できる場合は、それを使用してください。

たとえ安全であっても、それらのフィールドへのアクセスを同期せずにスレッド間で共有データを使用することはベスト プラクティスではありません。どのスレッドがオブジェクトを作成したかは問題ではありませんが、複数の実行行 (スレッド/プロセス) が同時にオブジェクトにアクセスしている場合は、データの不整合が生じる可能性があります。

このオブジェクトにアクセスするスレッドが 1 つだけであることが確実な場合は、アクセスを同期しないほうが安全です。それでも、後でアプリケーションの変更により、アクセスの同期を気にせずに同じデータを共有する 2 番目のスレッドが追加されるまで待つよりも、今すぐコードに同期を組み込んだ方が良いと思います。

はい、安全です。非常に一般的なパターンは、オブジェクトを作成し、それをキューまたは他のコレクションに追加することです。2 番目の「コンシューマ」スレッドはキューから項目を取得し、それらを使用して何らかの処理を行います。ここでは、キューを同期する必要がありますが、キューに追加されたオブジェクトは同期する必要はありません。

すべてを同期して最善の結果を期待するのは得策ではありません。デザインについて、またどのスレッドがオブジェクトに作用できるかを正確に考える必要があります。

考慮すべき点は次の 2 つです。

  • オブジェクトが他のスレッドで使用できるようになる前に、オブジェクトが完全に作成され、初期化されていることを保証できなければなりません。
  • データがロードされ、すべてが正常であることをメイン (GUI) スレッドが検出する何らかのメカニズムが必要です。スレッドセーフにするためには、必然的に何らかのロックが必要になります。

はい、できます、安全です

...2 人目のプログラマがやって来て、あなたが立てたのと同じ仮定を理解できなくなるまでは。その 2 人目 (または 3 人目、4 人目、5 人目...) のプログラマは、(作成者スレッドで) 安全でない方法でオブジェクトを使用し始める可能性があります。引き起こされる問題は非常に微妙であり、追跡するのが難しい場合があります。それだけの理由で、またこのオブジェクトを複数のスレッドで使用したくなるため、私はオブジェクトをスレッドセーフにします。

明確にするために、(コメントを残してくださった方々に感謝します):

「スレッドセーフ」とは、スレッドの問題を回避するためのスキームをプログラム的に考案することを意味します。必ずしもオブジェクトのロック スキームを考案するという意味ではありません。あなたの言語で、作成者スレッドでのオブジェクトの使用を違法 (または非常に困難) にする方法を見つけることができるでしょう。たとえば、作成者スレッド内のスコープを、オブジェクトを作成するコードのブロックに制限します。作成したら、オブジェクトをユーザー スレッドに渡し、作成者スレッドがオブジェクトへの参照を持たないようにしてください。

たとえば、C++ では

void CreateObject()
{
    Object* sharedObj = new Object();
    PassObjectToUsingThread( sharedObj); // this function would be system dependent
}

その後、作成スレッドではオブジェクトの作成後にそのオブジェクトにアクセスできなくなり、責任は使用スレッドに渡されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top