質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

3回答

13318閲覧

有効ではないスレッド間の操作の原因について

ibuki

総合スコア15

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

UI

UIはUser Interfaceの略であり、人間がコンピュータとやりとりをするためのシステムです。

スレッドセーフ

マルチスレッド環境において、複数のスレッド上で常に正常に実行する事が可能なコードを、スレッドセーフなコードと呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

1クリップ

投稿2018/02/27 07:20

編集2018/02/27 07:21

「System.InvalidOperationException: '有効ではないスレッド間の操作: 」
について、
マルチスレッドで動作中にオブジェクトの値を変更しようとすると例外が発生したので、調査しました。
その結果、UIコントロールは自身のUIスレッドからしかアクセスできないということなので、delegate やasync,awaitを使用することで解決できることが分かりました。
しかし、何故別のスレッドからUIコントロールにアクセスしようとするとエラーになるのかがいまいちピンと来ません。

これは私がスレッド自体に対しての理解が足りていないだけなのでしょうか?
それとも、そういうものだと思っておけば十分な感じでしょうか?

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

元々OS(Windows)が提供するウィンドウシステムでは、ウィンドウやコントロールに対して複数スレッドからのアクセスを許可しています。ただし、ウィンドウ(コントロール含む)操作は基本的にメッセージによって行われており、メッセージキューによりシリアライズされて、メッセージループにより単一のスレッドで実行される、という仕組みになっています。細かく説明すると長くなるので割愛しますが、これにより、C/C++でUIコントロールを複数スレッドでアクセスするようなプログラムを書く際は、よほど慎重に設計しないと簡単にデッドロックを引き起こします

OSの仕様としてそうなっている以上、言語レベルでそれを回避するのは不可能だと考えられます(可能だとしても途轍もなく複雑な処理になることが予想されます)。したがって、C#(.NET Framework)では、あえてUIコントロールのアクセスは単一スレッドのみに制限して別スレッドからのアクセスはエラーにさせることで、適切な設計を促しているのだと思います。

ちなみに、Invokeメソッドによる別スレッドからのUIコントロールのアクセスは、内部的にはメッセージ処理となるので、下手に使うと簡単にデッドロックを引き起こします

投稿2018/02/27 09:11

catsforepaw

総合スコア5944

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2018/02/27 09:32

自分もデッドロックを例にとってコメントしたのですが・・・ 考えてみると「MouseDown, MouseUp」みたいなイベントって「その順番に処理しなければ意味をなさない」と言えるので「イベントの処理を単一スレッドで順序性を保証してやらないといけないもの」という必然があり、その点もまた単一スレッドが前提となる理由と言える気がしました。
catsforepaw

2018/02/27 11:21

UIコントロールのデッドロックに関しては、排他制御におけるロックの取得・解放のタイミングの問題ではなく、UIコントロール操作がメッセージキューでシリアライズされた単一スレッドでの処理に起因することを知っておかないと、おそらく理解が難しいだろうと思い、その旨書いた次第です。 メッセージ駆動によるウィンドウシステムは、スレッドの概念のない頃からありましたが(いわゆるノンプリエンティブなマルチタスクOS)、キューイングの必要性は、当初は負荷の増大によるキーやマウス入力などの取りこぼし防止ではないかと推察します。それがマルチスレッドになると、操作がシリアライズされることでロック不要になるという副次的な効果をもたらした反面、デッドロックというリスクを抱えることになったわけですね。
KSwordOfHaste

2018/02/27 11:48

> ノンプリエンティブなマルチタスクOS、取りこぼし防止 なるほど様々な経緯を経てきた設計なので、どんな要因が設計根拠なのか色々考えられそうですね。
guest

0

しかし、何故別のスレッドからUIコントロールにアクセスしようとするとエラーになるのかがいまいちピンと来ません。

端的に言えば、その環境の「仕様」です。

マルチスレッドでの操作に対応するにはそれ相応のプログラミングコスト(作る側も使う側も)が必要となりますが、UIは人間の追える速度で入出力できればそれでいい環境ですし、1つのウィンドウにマルチスレッドでアクセスするのも煩雑化するため、シングルスレッドのみの対応とすることでことをシンプル化しています。

投稿2018/02/27 07:35

maisumakun

総合スコア145930

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ibuki

2018/02/27 07:57

マルチスでアクセスさせようと思えばできなくないだろうけど、コストや煩雑性、動作的な必要性の観点から、あえてできないようにしているということでしょうか?
maisumakun

2018/02/27 08:13

マルチスレッドに対する対応としては、何もしなかった場合「複数のアクセスが入ると矛盾してどうなるかわからない」ということになってしまいます。 それを防ぐには「真面目にマルチスレッド対応する」あるいは「1スレッドにしかアクセスさせない」などの対応法が考えられますが、UIスレッドの場合は1スレッド独占、という形を取った、という話です。
ibuki

2018/02/27 08:31

複数スレッドからアクセスがあったときに矛盾が発生するのを防ぐために、シングルスレッドでのみ動作するという形で解決を図った結果ということですね。 ご回答ありがとうございました。
guest

0

ベストアンサー

GUI処理がシングルスレッドに制限されるという考え方は「GUIプログラミングの性質からくる必然」に近いと自分は思っています。

マルチスレッドによる並行動作を正しく行えるためには「ある一定のルールによる行儀のよいアクセス順序」が確立された設計ができて、それに従ったプログラミングをすることが必要です。例えば「リソースAのロックをした上で何かの操作を行い、それが終わったらリソースAをリリースする」といった感じに。

ところがGUIというのは「依存関係が複雑に錯綜しているのが普通」です。
例えば「プログラム側で何かの計算をしてテキストフィールドにその結果を表示する」といった場合、ユーザーがテキストフィールドにアクセスできる以上は「プログラムが計算を開始する時点でテキストフィールドを操作できないようにロックする」なんてことが必要になるでしょう。では「結果を複数のコントロールへ反映させる」というような場合はどうなるでしょうか?それらのコントロールのロックを順番に全部取得してから計算を始めればよいでしょうか?

「複数のリソースをロックする」なんて設計は「ロック順序を少しでも設計し間違えると簡単にデッドロックを起こす」ためたいていの場合忌避されると思います。それをあえてやろうとしてもそんな複雑な設計を「GUIプログラミングをしようとしているアプリケーションプログラマーに要求する」のはあまり現実的とは言えないと自分は思います。


追記:思いつきに近い状態でコメントしたためいささか支離滅裂な内容になってしまったと思います。

例えば「依存関係が複雑に錯綜」は自動レイアウト機能をイメージしました。親部品と子供部品の間でレイアウト制約に従ってややこしい手順でレイアウトが決まる処理過程を「適切に排他制御する設計はやりきれないだろうな」といったことをイメージした内容だったのですが、それはGUIシステム一般についていえるような話ではなく特定のシステム固有の機能についての話であり、質問者さんが問いかけていることの焦点からははずれた内容だったと思います。

さらに上記をイメージしてロックの困難さを書こうとしたものの、前述のレイアウト動作の複雑さを説明するのがわかりにくそうだったためかけ離れた例(複数のコントロールへの状態反映の例)をかいちゃいました。

整理できてないままおかしな内容をコメントしてしまい失礼しました。

どちらかといえば「イベントが発生する順番にハンドリングする必要があり、そうした処理のシリアライズが必要だからこそ単一スレッドで設計するのが素直」とでも主張した方がまだましだったと思います。

投稿2018/02/27 08:10

編集2018/02/27 12:23
KSwordOfHaste

総合スコア18400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ibuki

2018/02/27 08:26

ご回答ありがとうございます。 きちんとマルチスレッドに対応するためには、GUIは複雑すぎてコストと結果が見合わないからということですね
KSwordOfHaste

2018/02/27 08:44 編集

コストがかかるというより「設計が不可能に近い」というのが自分の感覚です。 ---追記--- とはいえ、それは「うまい設計方法がある」ということを自分が知らないだけかも知れません。決して「多くのGUIシステムを知っている」というわけではないからです。自分が多少なりともそこそこ取り組んだことがあるのはWindowsのForm/WPF, Javaのswing/JavaFX, HTML/Javascript程度なのですがそれらはどれも基本的に単一スレッドでGUIを制御する設計になっています。ひょっとするとマルチスレッドで自由に制御できるようなGUIシステムがあるのかも知れません。そういうものがあるなら個人的に興味があるので設計を学んでみたいです。
ibuki

2018/02/27 08:41

考慮しないといけないことが多すぎてあまりに煩雑になりすぎるんですね
KSwordOfHaste

2018/02/27 08:45

>あまりに煩雑 はい、そう感じています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問