「System.InvalidOperationException: '有効ではないスレッド間の操作: 」
について、
マルチスレッドで動作中にオブジェクトの値を変更しようとすると例外が発生したので、調査しました。
その結果、UIコントロールは自身のUIスレッドからしかアクセスできないということなので、delegate やasync,awaitを使用することで解決できることが分かりました。
しかし、何故別のスレッドからUIコントロールにアクセスしようとするとエラーになるのかがいまいちピンと来ません。
これは私がスレッド自体に対しての理解が足りていないだけなのでしょうか?
それとも、そういうものだと思っておけば十分な感じでしょうか?
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
元々OS(Windows)が提供するウィンドウシステムでは、ウィンドウやコントロールに対して複数スレッドからのアクセスを許可しています。ただし、ウィンドウ(コントロール含む)操作は基本的にメッセージによって行われており、メッセージキューによりシリアライズされて、メッセージループにより単一のスレッドで実行される、という仕組みになっています。細かく説明すると長くなるので割愛しますが、これにより、C/C++でUIコントロールを複数スレッドでアクセスするようなプログラムを書く際は、よほど慎重に設計しないと簡単にデッドロックを引き起こします。
OSの仕様としてそうなっている以上、言語レベルでそれを回避するのは不可能だと考えられます(可能だとしても途轍もなく複雑な処理になることが予想されます)。したがって、C#(.NET Framework)では、あえてUIコントロールのアクセスは単一スレッドのみに制限して別スレッドからのアクセスはエラーにさせることで、適切な設計を促しているのだと思います。
ちなみに、Invoke
メソッドによる別スレッドからのUIコントロールのアクセスは、内部的にはメッセージ処理となるので、下手に使うと簡単にデッドロックを引き起こします。
投稿2018/02/27 09:11
総合スコア5944
0
しかし、何故別のスレッドからUIコントロールにアクセスしようとするとエラーになるのかがいまいちピンと来ません。
端的に言えば、その環境の「仕様」です。
マルチスレッドでの操作に対応するにはそれ相応のプログラミングコスト(作る側も使う側も)が必要となりますが、UIは人間の追える速度で入出力できればそれでいい環境ですし、1つのウィンドウにマルチスレッドでアクセスするのも煩雑化するため、シングルスレッドのみの対応とすることでことをシンプル化しています。
投稿2018/02/27 07:35
総合スコア145930
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/02/27 08:13
2018/02/27 08:31
0
ベストアンサー
GUI処理がシングルスレッドに制限されるという考え方は「GUIプログラミングの性質からくる必然」に近いと自分は思っています。
マルチスレッドによる並行動作を正しく行えるためには「ある一定のルールによる行儀のよいアクセス順序」が確立された設計ができて、それに従ったプログラミングをすることが必要です。例えば「リソースAのロックをした上で何かの操作を行い、それが終わったらリソースAをリリースする」といった感じに。
ところがGUIというのは「依存関係が複雑に錯綜しているのが普通」です。
例えば「プログラム側で何かの計算をしてテキストフィールドにその結果を表示する」といった場合、ユーザーがテキストフィールドにアクセスできる以上は「プログラムが計算を開始する時点でテキストフィールドを操作できないようにロックする」なんてことが必要になるでしょう。では「結果を複数のコントロールへ反映させる」というような場合はどうなるでしょうか?それらのコントロールのロックを順番に全部取得してから計算を始めればよいでしょうか?
「複数のリソースをロックする」なんて設計は「ロック順序を少しでも設計し間違えると簡単にデッドロックを起こす」ためたいていの場合忌避されると思います。それをあえてやろうとしてもそんな複雑な設計を「GUIプログラミングをしようとしているアプリケーションプログラマーに要求する」のはあまり現実的とは言えないと自分は思います。
追記:思いつきに近い状態でコメントしたためいささか支離滅裂な内容になってしまったと思います。
例えば「依存関係が複雑に錯綜」は自動レイアウト機能をイメージしました。親部品と子供部品の間でレイアウト制約に従ってややこしい手順でレイアウトが決まる処理過程を「適切に排他制御する設計はやりきれないだろうな」といったことをイメージした内容だったのですが、それはGUIシステム一般についていえるような話ではなく特定のシステム固有の機能についての話であり、質問者さんが問いかけていることの焦点からははずれた内容だったと思います。
さらに上記をイメージしてロックの困難さを書こうとしたものの、前述のレイアウト動作の複雑さを説明するのがわかりにくそうだったためかけ離れた例(複数のコントロールへの状態反映の例)をかいちゃいました。
整理できてないままおかしな内容をコメントしてしまい失礼しました。
どちらかといえば「イベントが発生する順番にハンドリングする必要があり、そうした処理のシリアライズが必要だからこそ単一スレッドで設計するのが素直」とでも主張した方がまだましだったと思います。
投稿2018/02/27 08:10
編集2018/02/27 12:23総合スコア18400
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/02/27 08:26
2018/02/27 08:44 編集
2018/02/27 08:41
2018/02/27 08:45
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/02/27 09:32
2018/02/27 11:21
2018/02/27 11:48