同じウィンドウに複数のUIスレッド

multithreading thread-safety user-interface

それぞれ独自のUIスレッドを持つ複数のウィンドウも、バックグラウンドワーカーや通知でもなく、単一のUIスレッドで発生するイベントも、そのInvokeやBeginInvokeのものも必要ありません。

  • 私は安全に複数のスレッドが同じウィンドウを更新できるようにするプラットフォームに興味があります。 最初のスレッドが3つのボタンを作成し、2番目のスレッドがさらに5つを作成します。それらは両方とも、それらにアクセスし、それらのプロパティを変更し、それらを不要な結果なしに削除できます。

  • Invokingを使わずにUIに安全にマルチスレッドでアクセスできるようにしたい。「オブジェクトはそれを作成したスレッドからしかアクセスできない」などのエラーを発生させることなく、どのスレッドからでもUIオブジェクトに直接アクセスできます。 必要に応じて同期を実行できるようにするために、直接の方法でUIにクロスアクセスすることを防ぎません。

  3  2


ベストアンサー

私は投票されるつもりだが…​ ガジェットソープボックスを行く。

マルチスレッドGUIは一般的には不可能です。 それは何度も何度も試みられてきました、そしてそれは決してうまく出ません。 すべての主要ウィンドウ枠組みがシングルスレッドのuiモデルに従うのは偶然ではありません。 彼らはお互いをコピーしていませんでした、それは問題の制約が彼らに同じ答えを導いたということです。 あなたよりも賢い多くの人々、または私はこれを解決しようとしました。

特定のプロジェクトにマルチスレッドUIを実装することは可能かもしれません。 私はそれが一般的な場合にはできないと言っているだけです。 つまり、あなたが望むことをするためのフレームワークを見つけることはまずないでしょう。

問題の要旨はこれです。 guiコンポーネントをチェーンとして想像してみてください(実際にはツリーのようなものですが、チェーンは説明が簡単です)。 ボタンはフレームに接続し、ボックスに接続し、ウィンドウに接続します。 システム/ OSとユーザーの2つのイベントのソースがあります。 システム/ OSイベントはチェーンの最下部(ウィンドウシステム)から発生し、ユーザーイベントはチェーンの最上部(ボタン)から発生します。 これらの出来事は両方ともgui chainを通り抜けなければなりません。 2つのスレッドがこれらのイベントを同時にプッシュしている場合、それらはミューテックスで保護されている必要があります。 しかしながら、二重リンクリストを両方向に同時に横断するための既知のアルゴリズムは存在しない。 デッドロックが発生しやすいです。 GUIの専門家は、デッドロックの問題を回避する方法を見つけようとしましたが、最終的に今日使用しているModel / View / Controllerと呼ばれる1つのスレッドでUIを実行するソリューションに到達しました。

16


スレッドセーフなプロデューサー/コンシューマーのデリゲートキューを作成できます。 UIコンポーネントを更新したいスレッドは、実行する操作をカプセル化したデリゲートを作成し、それをキューに追加します。 UIスレッドは(すべてのコンポーネントが同じスレッド上に作成されたと仮定して)、キューからアイテムを定期的に引き出し、デリゲートを実行します。

7


そのようなプラットフォームが存在するとは思わない。

NETを使用してスレッドセーフで、そのように動作することができるすべての新しいコントロールを作成するのを止めるものは何もありません。なぜなら、ベースコントロールから派生させて、スレッドセーフでないメソッドやプロパティをオーバーライドするだけだからです。

しかし本当の質問はなぜですか? すべてのロックのために確かに遅くなります。 あるスレッドでUIを使って何かをしているとしましょう、それはそれが働いているウィンドウをロックしなければなりません。 そのため、すべてのロックを使用すると、描画時間のほとんどを費やすことになり、ロックの待機やスレッドからの(高価な)コンテキストの切り替えが行われます。 あなたはそれを非同期にすることもできますが、あなたが作成したばかりのコントロールは存在してもしなくてもいいようなので安全ではないようです(おそらくそうではありません)。

Panel p=new Panel();
Button b=new Button();
WaitForControlsCreated(); //waits until the current control queue is cleared
p.Controls.Add(b);

これはおそらく同じくらい遅いです..

それで、ここで本当の質問はなぜですか? それを行う唯一の「良い」方法は、 `invoke`を抽象化して、UI以外のスレッドからコントロールを追加できるように見せることです。

スレッドが実際にどのように機能するのか、そしてオブジェクトスレッドを実際に安全にするために必要なことは、あなたが誤解していると思います。

3


GUIを更新するコードはすべてGUIスレッド上になければならないことを受け入れます。 BeginInvoke()の使い方を学びましょう。

2


Windowsでは、 http://blogs.msdn.com/oldnewthing/archive/2005/10/10/479124.aspx[ウィンドウハンドルはスレッドアフィニティを持ちます。 これはウィンドウマネージャの制限です。 Windows上で複数のスレッドが同じウィンドウにアクセスするのは悪い考えです。

1


私はこれらの答えを見て驚いた。

C#のような高級言語フレームワークだけがGUI要素に対するスレッド制限を持っています。

SDK層では、Windowsは100%アプリケーション制御されており、重要度がわずかである場合を除き、スレッドに対する制限はありません。 たとえば、複数のスレッドがウィンドウに書き込みたい場合は、ミューテックスをロックし、デバイスコンテキストを取得し、描画してからコンテキストを解放してから、ミューテックスのロックを解除する必要があります。 描画中のデバイスコンテキストの取得と解放は、同じスレッド上で行う必要があります。 しかし、それらは通常互いに10行以内のコードです。

“DispatchMessage()”を呼び出すスレッドがWINPROCが呼び出されるスレッドである場合は、Windowsメッセージが表示される専用のスレッドもありません。

もう1つのマイナースレッドの制限は、現在のスレッド上に作成されたウィンドウの “PeekMessage”または “GetMessage”のみです。 しかし、実際にはこれはごくわずかなものです。とにかく、メッセージポンプをいくつ使用する必要があります。

描画はWindowsのスレッドから完全に切り離されています。描画用にDCをミューテックスするだけです。 WM_PAINTメッセージだけでなく、いつでもどこからでも描画できます。

1


0


私の推測では、単一のWindowsフォームが必要で、特定のルーチンを非同期的に実行する方法(マルチスレッドなど)が必要です。

通常(.NET WinFormsの場合)、 Control.Invoke /` Control.BeginInvoke`は、あなたが望むと思われる効果を得るために使用されます。

これは役に立つかもしれない興味深い記事です:http://www.yoda.arachsys.com/csharp/threads/winforms.shtml

-1


タイトルとURLをコピーしました