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

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

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

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

Q&A

解決済

1回答

2099閲覧

Task.WhenAll から先に進まない

ohno1011

総合スコア14

C#

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

0グッド

0クリップ

投稿2021/07/15 06:06

お世話になります。

Taskを使用した非同期処理で解決できない現象があり、質問させて頂きます。
非同期処理をする目的は、フォームのフリーズを防ぐため、複数のデータ作成処理を並行して行いたいためです。

1.ソリューション内にプロジェクト Main, A があります。
2.Mainプロジェクトのフォーム操作からのイベントから、Aプロジェクト内のclass_AクラスのMainメソッドを呼び出しています。
3.class_AクラスのMainメソッドでループ処理をし、その中でMakeDataメソッドを呼び出しています。
4.サンプルソースにはAデータを作るタスクしか書いてありませんが、実際には複数のタスクがあり、
WhenAll(task_A, task_B, task_C, ...) という形になりますが、テストでtask_Aだけにしていますが、1つだけでも問題が起きています。

ソース

Mainプロジェクト

C#

1private async void A_Load() 2{ 3 class_A cls_A = new cls_A(); 4 await Task.Run(async() => 5 { 6 await cls_A.Main(); 7 }); 8}

Aプロジェクト class_A.cs

C#

1public async Task<bool> Main() 2{ 3 for(int i = 0; i < 100; i++) 4 { 5 if(await MakeData(i) == false) 6 { 7 return false; 8 } 9 } 10 return true; 11} 12 13private async Task<bool> MakeData(int i) 14{ 15 Task task_A = Task.Run(() => 16 { 17 clsCreateData_A Create_A = new clsCreateData_A(); 18 int Count_A = 0; 19 string strCreateData_A = Create_A.CreateData_A(i, ref Count_A); 20 if(strCreateData_A == "") 21 { 22 Console.Writeline("Aデータ:" + Count_A.ToString() + "件"); 23 } 24 else 25 { 26 //エラー処理 27 reutrn false; 28 } 29 }); 30 31 await Task.WhenAll(task_A); 32 33 return true; 34}

Aプロジェクト clsCreateData_A.cs

C#

1public string CreateData_A(i, ref Count) 2{ 3 return ""; 4 5 //実際には下にコードが続きますが試験的に止めてすぐreturnを返すようにしています。 6 //これでも問題は発生しています。 7}

このような処理で、await Task.WhenAll(task_A); から先に進まずに止まってしまいます。

確認したこと

1.CreateData_Aの中身が関係しているのか確認するために、すぐreturnを返すようにしましたがTask.WhenAllで止まってしまいます。

C#

1Task Task_A = Task.Run(() => 2{ 3 Console.WriteLine("AAA") 4} 5await Task.WhenAll(Task_A);

2.上記のようにしてTask内での別クラス呼び出しを止めて簡単なコードにしたところ、問題なく進みました。
3.Task.WhenAllの代わりにTask_A.Wait(); とすると、問題なく進みました。
4.await Task.WhenAll(Task_A) をawait Task.WaitAll(Task_A) に変えると、CS4008 'void'を待機することができません というエラーが発生します。
await を外して Taks.WaitAllとすると、フォームもフリーズせず臨んだ通りの動作をしますが、
CS1998 この非同期メソッドには'await'演算子がないため~ という警告が出ています。
await を使っていないので、MakeDataメソッドの async を外すと、return のところで

CS0029 型 'bool' を 'System.Threading.Tasks.Task<bool>' に暗黙的に変換できません

というエラーが発生します。

async がない場合の Task<bool> の返り値にはどのように返せばよいのか、調べても理解できませんでした。

エラー、警告が無く動作するようにはどうしたら良いか、アドバイスが欲しいです。
Taskについての知識も浅いので、もっと良い書き方もあるかと思います。

よろしくお願い致します。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/07/15 06:34 編集

とりあえず、コンパイル出来て問題が再現できる状態の必要最小限のコードを提示してください。 現在質問に提示しているコードではコンパイル通らないです。
ohno1011

2021/07/15 06:49

回答ありがとうございます。 すみませんが、今回問題が起きていた部分のみを動作するようにコードを残して実行したところ、 await Task.WhenAll(task_A)でも問題なく進みました... 元のコードから少しずつ削ってどこで問題が発生するのか、詰めていきたいと思います。
guest

回答1

0

自己解決

解決しました。
サンプルコードからは省いてしまっていましたが、
Mainプロジェクトの private async void A_Load()の中で
今回の目的のコードとは別件で書き足したコードに問題がありました。
これもまだテスト中だったことですが、
AプロジェクトからMainプロジェクトのフォームの
テキストボックスに処理履歴の書き込みをできないか ということをしようとしており、
フォームの情報を渡すために

C#

1private async void A_Load() 2{ 3 class_A cls_A = new cls_A(); 4 await Task.Run(async() => 5 { 6 Form1 F1 = new Form1(); ★ 7 await cls_A.Main(F1); 8 }); 9}

Taskの中でFormを宣言してcls_Aに渡していました。
このFormの宣言をTaskの外に出すことで解決しました。

大変失礼しました。

投稿2021/07/15 07:06

ohno1011

総合スコア14

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問