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

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

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

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

非同期処理

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

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

Q&A

解決済

1回答

8189閲覧

別スレッドからのコントロールのInvokeについて

hayamura.akito

総合スコア3

C#

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

非同期処理

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

検索

検索は、あるデータの集まりの中から 目的のデータを見つけ出すことです。

0グッド

0クリップ

投稿2021/06/23 04:07

編集2021/06/23 04:34

C#で対戦型カードゲームを作成しています。
Socketによる通信を介して対戦の機能を実装しようとしていて、現在はフォームの遷移を行う機能を実装しています。

二人のユーザの準備が完了すれば、サーバからゲーム開始の通知が送信され、それを受信したのちにそれぞれのユーザがゲーム用のフォームへと遷移する機能を実装しています。

遷移前のフォームから遷移先のフォームへ移る際の処理の中でInvokeメソッドを呼んでいるのですが、その際にプログラムが停止してしまいます。
デバッグでステップ実行をしても、その前段階でエラーなどは起きておらず、Invokeメソッドを実行する段階で急に止まってしまいます。エラーメッセージなども出ないため、どのように調べればよいかも分かりません。

何とか他に使えるメソッドがないか調べ、InvokeメソッドをBeginInvokeメソッドに変えることでプログラム自体は動くようになったのですが、なぜBeginInvokeメソッドに変更するとプログラムが停止しなくなるのかが分かりません。

この現象について何が起こっているのかが知りたいです。
具体的に何が起こっているかや、どのような検索キーワードで調べればよいかなど、教えてください。

下記に関係がありそうな部分のソースコードは記載していますが、足りない情報などがあればそれも教えてください。

発生している問題・エラーメッセージ

コントロールのInvokeメソッドを呼ぶとプログラムが停止する。 (追記) エラーメッセージは出力されませんでした。

該当のソースコード

フォームの遷移を行うための記述

C#

1static class Program 2 { 3 private static ApplicationContext mainApplicationContext; 4 /// <summary> 5 /// The main entry point for the application. 6 /// </summary> 7 [STAThread] 8 static void Main() 9 { 10 Application.SetHighDpiMode(HighDpiMode.SystemAware); 11 Application.EnableVisualStyles(); 12 Application.SetCompatibleTextRenderingDefault(false); 13 mainApplicationContext = new ApplicationContext(); 14 15 View.StartView view = new View.StartView(); 16 view.FormClosed += new FormClosedEventHandler(FormClosed); 17 mainApplicationContext.MainForm = view; 18 Application.Run(mainApplicationContext); 19 } 20 private static void FormClosed(object sender, EventArgs e) 21 { 22 if (sender.GetType().BaseType != typeof(View.ViewBase)) { return; } 23 24 View.ViewBase NextView = ((View.ViewBase)sender).NextView; 25 if (NextView == null) { return; } 26 mainApplicationContext.MainForm = NextView; 27 NextView.FormClosed += new FormClosedEventHandler(FormClosed); 28 NextView.Show(); 29 } 30 }

画面遷移をするフォームに継承しているViewBase

MoveViewメソッドを呼んでデバッグしながらステップ実行をすると、
Invoke(d, new object[] { view });
の行でプログラムが停止してしまいます。

C#

1internal class ViewBase : Form 2 { 3 private delegate void MoveNextView(ViewBase view); 4 internal ViewBase NextView { get; set; } 5 6 internal void MoveView(ViewBase view) 7 { 8 if (InvokeRequired) 9 { 10 var d = new MoveNextView(MoveView); 11 Invoke(d, new object[] { view }); 12 } 13 else 14 { 15 NextView = view; 16 Close(); 17 } 18 } 19 }

試したこと

InvokeメソッドをBeginInvokeメソッドに変更する
=>プログラムは停止しないようになったが理由が分からない。

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

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

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

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

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

BluOxy

2021/06/23 04:10

> コントロールのInvokeメソッドを呼ぶとプログラムが停止する。 エラーメッセージはどのような内容でしょうか
neconekocat

2021/06/23 04:26

何で止まるかっていうとデッドロックが起きてるからです。 BeginInvokeは即座に制御を返すのでスレッドをロックしません。
hayamura.akito

2021/06/23 04:32

>>BluOxyさん エラーメッセージは何も出ませんでした。 追記しておきます。
hayamura.akito

2021/06/23 04:43

>>neconekocatさん ありがとうございます。 InvokeとBeginInvokeの違いについて少しですが理解できました。 また、「コントロール Invoke デッドロック」で検索することで、関連のありそうなページを何件か見つけることができました。
guest

回答1

0

ベストアンサー

ViewBase.MoveView が呼ばれる際に,GUIスレッドが停止しているのではないでしょうか.
(例えば,それを呼ぶ側の終了を待っているとか)

  • Invokeの場合:GUIスレッドに処理させたいけどGUIスレッドは停止しているからそこで止まっちゃう(デッドロック)
  • BeginInvokeの場合:BeginInvokeはGUIスレッドにやってほしい処理を予約するだけなので,そこではGUIスレッドが停止してても大丈夫.

で,その後で(何かがあって)GUIスレッドが動き出してのちに,その予約処理が実施される.
だから止まらない.

投稿2021/06/23 04:24

編集2021/06/23 04:41
fana

総合スコア11996

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

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

hayamura.akito

2021/06/23 04:50

ありがとうございます。 neconekocatさんもご回答いただいていましたが、やはり、Invokeを呼んだ際にデッドロックが起こっていたようです。 「コントロール Invoke デッドロック」で検索することで、関連のありそうなページを見つけることができました。 https://docs.microsoft.com/ja-jp/dotnet/standard/parallel-programming/potential-pitfalls-in-data-and-task-parallelism?redirectedfrom=MSDN#avoid-executing-parallel-loops-on-the-ui-thread まだすべての内容の理解はできていませんが、どのようなキーワードで検索すればよいか全くわからず、苦労していたため大変助かりました。 現在はご回答いただいた内容で検索をかけることで目的の情報までたどり着けると思いますのでこの質問はクローズさせていただきます。
fana

2021/06/23 05:02

そこに > Invoke の呼び出しによって UI スレッドにメッセージが送信され、そのメッセージが処理されるのを待機することになります とか書いてありますね. UIスレッドがそのメッセージを処理しない限りは,Invokeからは処理が返らない.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問