Rustでは、Send
(またはSync
)マーカー特性を使用して、スレッドコンテキスト内で型の値(またはその参照)を処理できるかどうかを示します。
ただし、C関数のマンページ(man 3 Rand
など)で頻繁に見られるように、スレッドセーフかどうかは関数またはプロシージャの属性です。
では、なぜRustは、このような属性を関数ではなくデータ型に適用するように設計されているのですか?
struct Foo { ... }
unsafe sync fn thread_safe_fn(foo: &Foo) { ... }
このように、どの型もどこでも使用できますが、共有データを操作できるのはsync
関数だけです。これにより、たとえば、アトミック(Rc
)または非アトミック(!sync
)のいずれかの定義済み演算を持つ単一のsync
を持つことが可能になります。
共有されるdataが変更される可能性があること、およびどのようにそのデータを保護するかを認識すること以外に、スレッドセーフを意味する関数に固有のものはありません。メモリ内に存在するデータ自体であり、個別の実行スレッドからアクセスでき、通常は関数ではありません(ロード後にコードが変更される関数がある場合を除きますが、それははるかにまれです)。 CのRand()
関数の場合、その実装は共有データにアクセスし、同時アクセスから保護しません。マンページから、「関数Rand()
は、呼び出しごとに変更される非表示の状態を使用するため、再入可能ではありません。」
言語が記述どおりに記述されている場合は、ユーティリティ関数がFoo
を変更する状況を考慮してください。このユーティリティ関数がスレッドセーフとしてマークされている場合、不必要にロックを取得し、(必ずしも)共有されていないデータを保護する必要があります。さらに、同じメモリ位置への同時アクセスからのスレッドのみをブロックし、関数内のすべてのエントリポイントへのアクセスをブロックしないようにします。これは、特定の部分を保護するものではなく、汎用関数が実行をシリアル化する必要がある場合に少し扱いにくくなります。データの。
struct Foo { ... } unsafe sync fn thread_safe_fn(foo: &Foo) { ... }
このように、どのタイプもどこでも使用できますが、共有データを操作できるのは同期機能だけです。これにより、たとえば、アトミック(同期)または非アトミック(!sync)のいずれかの定義済み操作を持つ単一のRcを持つことが可能になります。
スレッド化された競合状態からデータ構造を保護するには、そのデータ構造へのすべてのアクセスを、一部だけでなく保護する必要があります。 (プロセッサーによっては、読み取りと書き込みを適切に調整する必要があるため、読み取りだけでなく書き込みの保護も含まれます。)
提案するアプローチの1つの問題は、システムが不適切な使用法を特定することが困難になることです。同期呼び出しと非同期呼び出し(Cの場合)をいつ、どこで使用するかはプログラマ次第です。コンパイラーは、プログラムが誤りを犯しているかどうかを判別できません。
Rustコンパイルシステムは、RcとArcに別々のタイプを持たせることで、Rcの不適切な使用を検出し、エラーとしてフラグを立てることができます。Rustがこれを行うため、プログラムコンパイルに合格すると、特定の種類の正当性の証明可能なプロパティがあります。
どこでも単純にArcを使用できますが、必要のない場合はコストがかかるため、Rcも提供されます。非スレッドセーフデータに対するこれらの不正な操作を検出するのはタイプシステムです。スレッドセーフと非スレッドセーフの両方のアクセスに単一の共通データタイプを使用すると、Rustはそれを実行できません。特定の望ましいプログラムプロパティを保証する仕事。
なぜCは、たとえば、関数Rand
はスレッドセーフではないが、他の関数はそうであると説明しないで済むのでしょうか。
プライベートグローバルステートを使用しているため、Rand
はnotスレッドセーフであると彼らは言っています。スレッドセーフとして説明されている他の関数は、単にグローバルステートを持たない—本質的にスレッドセーフにする適切な使用法で —で使用されているパラメーターを提供するのは呼び出し元の責任ですスレッドセーフな方法。 Cのスレッドセーフティの主張はかなり弱いです。基本的に、プログラマが開発者が実現するスレッドセーフティの可能性は、Rustの保証と比較して弱いです。
「スレッドセーフティ」の質問は、基本的に「複数の異なるスレッドで複数の操作を使用して共有の可変データを変更した場合、正しい結果が得られるかどうか」を意味します。
したがって、スレッドセーフのしくみについてthinkingがなくても、上記の文英語を非常に愚かに分析しましょう。 「スレッドセーフ」などのプロパティを1つの場所に配置したい場合、どこに配置できますか?スレッドが複数あるため、スレッドに入れることができません。複数の操作があるため、操作に含めることができません。 唯一の場所それを置くデータ上!