web-dev-qa-db-ja.com

メソッドの動作を呼び出し元のスレッドに依存させるのは良い考えですか?

スレッドセーフにするために、サードパーティのクラスをサブクラス化したい。

これを実装する方法については良い考えがありますが、問題があります。スーパークラスには、そのメソッドの1つの動作に影響を与えるプロパティがあります。 1つのスレッドがプロパティを設定すると、他のスレッドがメソッドを呼び出すときに干渉します。

これを行うには2つの方法があります。

  1. スレッドセーフな「ステートレス」オブジェクトを作成します。このオブジェクトには、複数の「ビュー」があります。プロパティはビュー内にあり、各スレッドには独自のビューインスタンスがあります。
  2. プロパティのgetアクセサーとメソッドでどのスレッドが呼び出しを行うかを検出し、そのスレッドの状態を内部に保存します。

(1)は自明ですが、より多くの定型コードが含まれます。 (2)舞台裏で重要なことをしますが、それが機能する場合、それは完全に透過的です。

保守性と読みやすさのどちらが最適ですか?より複雑なコードですが、その動作は前もって行われていますか、それとも動作時に使いやすいコードですが、壊れた場合は、明らかではない場所と方法で動作しますか?

オブジェクトがnotどのスレッドと相互作用するかに依存する必要がある理由はありますか?

(編集:実装の要件は思ったほど単純ではなく、必要以上に混乱を引き起こしていたため、サードパーティクラスへの参照を削除しました!)

2
sebf

スレッド固有の変数を持つという考えは不合理ではありませんが、それがあなたのユースケースに適しているかどうかはわかりません。スレッドセーフなStreamのアイデアは、少し壊れているように私を驚かせます。むしろスレッドセーフなStreamFactoryが欲しいです。

スレッド固有の状態変数を実装する最良の方法は、 ThreadStatic または ThreadLocal<T> のいずれかを使用することです。これにより、コードが短く、シンプルになり、簡単に保守できるようになります。この変数は、Streamのメンバーになります。

使用する議論については、 ThreadStatic v.s. ThreadLocal:は属性よりも一般的ですか? を参照してください(短いバージョン:.Net4以降を使用している場合はThreadLocal<T>を使用してください)。

6
Brian

これはあなたの質問に答えませんが:

  1. スレッドセーフにするために、サードパーティのクラスをサブクラス化することはお勧めできません。作成者はクラスを設計するときにスレッドセーフを考えていなかった可能性が高いため、可能であれば、サブクラス化してスレッドセーフを追加することは非常に困難です。ポリモーフィズムとスレッドセーフを同時に考えるのはやりすぎです。クラスの実装が変更された場合はどうなりますか?
  2. スレッドセーフなストリームを作成することはお勧めできません。ストリームを2人のリーダーで同時に読み取ることはできないのに、なぜわざわざ複数のスレッドからストリームにアクセスするのでしょうか。 偶発的な複雑さ
7

面白い。 Delphiでは、変数をthreadvarとして宣言できます。これにより、すべてのスレッドに独自のコピーが確実に作成されます。ただし、これらはグローバル変数であるため、欠点があります。そこで、同僚が「スレッドスタンス」データを思いついたのです。スレッドとインスタンスの両方に固有のデータ。オプション2と非常によく似ています。それはうまく機能し、美しく機能します。

今日の選択を考えると、私はオプション1に行きます。

オプション2を使用すると、他の開発者にとって完全に透過的になる可能性がありますが、それが必ずしも良いことだとは思いません。そのクラスの「スレッド依存」の性質を曖昧にするという代償を伴います。開発者が常に知っておくべきこと。

オプション1はすべてをより明確にします、そして私、私は明示的に好きです。

2
Marjan Venema

明らかなことですが、同期されたストリームを作成することは、ほぼ完全に無意味です。1

蒸気の内部がマルチスレッドによって壊されないようにすることができないというわけではありません。それは実際には本当に簡単です。
問題は、ほとんどすべてのコードがストリームへの暗黙の排他的アクセスに依存して、概念的にアトミックな出力が任意に中断されたり、相互に中断されたりしないようにすることで発生します。これにより、出力がフラットになります。役に立たない。

複数のスレッドが同じスレッドにアクセスできる場合、それらはプログラマーであるあなたに依存し、とにかく論理単位でアクセスを賢明に同期します。

例外に関しては、出力が論理単位でストリームに移動されることを確認する場合(全員がオンボードしている場合、または転送ストリームを使用している場合)は数回ですが、これは自動フラッシュされません))、または物事が非常に壊れているため、エラーメッセージを記述し、最善を期待し、とにかく中止することしかできません。

0
Deduplicator