0

私は C# で作成したアプリケーションを持っていますが、ここでは同様の言語が適用されます。

アプリケーションには、さまざまな UDP および TCP ソケットを介して受信したデータに基づいて、フォーム上のウィンドウにリアルタイムでグラフィック シーンを描画するジョブがあります。UDP および TCP 接続はそれぞれ独自のスレッドを使用します。これらのスレッドはそれぞれ、メモリ内のさまざまなオブジェクトを変更し、それによってグラフィック表示が変更されます。また、ユーザー イベント (ボタンのクリックなど) を受け取ることができるユーザー インターフェイス スレッドもあり、それらの同じオブジェクトと表示が変更されます。最後に、同じオブジェクトと表示を変更する独自のスレッドを起動する多くのタイマーも起動します。

変更されているメモリ内のオブジェクトは、約 15 の異なるクラスで構成されています。

すべてがかなり確実に機能しますが、さまざまなクラスがさまざまなスレッドによって変更されるため、多くの同期ロックを追加する必要がありました。どのメモリが複数のスレッドによって変更される可能性があるかを判断するために、各クラスを個別に調べる必要がありました。

この状況では、これらのスポットの 1 つを見逃すのは非常に簡単に思えます: 必要な場所に同期を追加するのを忘れてしまうのです。

他の人が私が行った方法でこれを実装するかどうか、またはもっとエレガントな方法があるかどうかについて興味があります。おそらく、クラス A のすべての変更を独自のスレッドまたは何かに配置するのでしょうか?

(追記: 最初はうまくいかなかったので、ここで質問するのはとても怖いです。しかし、ここでの私の質問はあまり明白ではないと思うので、あなたもそうしないことを願っています。;o )

4

1 に答える 1

1

これには明確な答えはないと思います。

私は他の人が同様の状況に対処するためにデザインを変更するのを手伝いました。最も一般的に使用される手法の 1 つは、より良い抽象化を導入することです。

たとえば、ユーザー マップとアクティブ ユーザー セットをロックし、スレッドに手動でロックを取得させる代わりに、ユーザーを含むマップとアクティブ ユーザーを含む別のセットを更新する必要がある複数のスレッドがあるとします。抽象化呼び出し UserRepository を導入します。これには、ユーザー マップとアクティブ ユーザー セットが含まれます。UserRepository は、他のユーザーが UserRepository を操作するためのビジネス上意味のあるメソッドを提供します。ロックは、呼び出し元によって明示的に取得されるのではなく、UserRepository のメソッドで取得されます。

私の過去の経験から、複雑な同期の 80% 以上は、上記の例のように設計を改善することで大幅に簡素化できます。

他のテクニックも可能です。たとえば、更新を非同期で実行しても問題ない場合は、スレッドでリソースを直接更新する代わりに、コマンド オブジェクトを作成してプロデューサー/コンシューマー キューに入れ、専用スレッドで更新を実行することができます。

また、ロックの数が少ない方が扱いやすい場合もあります。たとえば、複数のリソースを更新する場合、リソースごとに 1 つのロックを使用する代わりに、更新をアクション全体として見ることができ、スレッド間の調整に 1 つのロックのみを使用できます。当然競合が増えますが、競合は大した問題ではなく、保守性が欲しいというケースもあります。

同様の状況に対処する方法は他にもたくさんあると思います。以前の経験の一部を共有しているだけです(うまくいきました:P)

于 2013-01-07T01:49:07.180 に答える