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

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

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

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

Q&A

解決済

1回答

2700閲覧

子タスクが複数ある場合に一方の子タスクが完了待ちしてこない

matsu1

総合スコア19

C#

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

0グッド

0クリップ

投稿2016/08/23 01:42

編集2016/08/23 04:03

###前提・実現したいこと
お世話になります。
C#で2つのタスクA,Bを並列で動作させている状態で、さらに各タスクが子タスクを持っているシステムを作成しています。わかりやすいように以下では例を用いて説明させて頂きます。

①タスクA:ネットワーク接続確認を行う。
②タスクB:ネットワーク越しのフォルダ間コピーを行う。
③子タスク:
タスクA,Bで用いる子タスクは共通のクラスを用いており、
・タスクAの子タスクは"ping 接続先IPアドレス"
・タスクBの子タスクは"copy コピー元フォルダパス コピー先フォルダパス"
というコマンドをSystem.Diagnostics.Processで実行させ、実行完了するまで待つタスクです。

タスクAでは子タスクのpingの実行結果を用いて接続判定(接続or切断)を行います。
タスクBでは子タスクのcopyの実行結果を用いてコピー成否判定(成功or失敗)を行います。
タスクA,Bともに子タスクの実行完了はawaitで待ち、awaitの次の行で上記の結果を用いた判定を
行わせています。

###発生している問題・エラーメッセージ
タスクAでは子タスクのawaitで待ち完了→次の行で結果を用いた判定ができています。
タスクBでは子タスクのawaitで待ち→いつまで経っても次の行に来ないため結果を用いた判定ができません。
タスクBでも、判定ができるようにしたいのですが原因がわからず、ご教授をお願い致します。

###該当のソースコード
以下にコードを記載します。
下記の★1(GetIsConnect()内のawaitの次の行)には来ますが、★2(CopyFolder()内のawaitの次の行)には
いつまで経っても来ません。ここに来るようにしたいのですが原因がわからずで、ご教授をお願い致します。
なお、ExeCommandTask()はタスクA,Bの子タスクであるため、StartNew時にAttachedToParent指定
しています。
タスク設計に熟達しておらず、使い方が誤っている箇所もあるかと思いますが、それも併せて教えて
頂けますと幸いです。よろしくお願い致します。

------------------------- メインクラス:CMainのメンバ変数,関数 -------------------------

◆/* @brief タスクA,Bのキャンセルトークンソース */
CancellationTokenSource m_CTSTaskA = new CancellationTokenSource();
CancellationTokenSource m_CTSTaskB = new CancellationTokenSource();

◆/* @brief タスクA,Bを非同期で並列に実行する */
public async void ExeTaskAandB()
{
var t1 = TaskA();
var t2 = TaskB();
await Task.WhenAll(t1, t2);
}

◆/* @brief タスクA:ネットワーク接続確認を行う */
private Task TaskA()
{
return Task.Factory.StartNew(() => {
while (true) {
if (GetIsConnect().Result == 1) {// 接続と判定}
else {// 切断と判定}
Task.Delay(2000, m_CTSTaskA.Token);
}
}, m_CTSTaskA.Token);
}

◆/* @brief ネットワーク接続確認をプロセスで行う */
private async Task<int> GetIsConnect()
{
CCommon common = new CCommon();
string result = await common.ExeCommandTask(m_CTSTaskA, "ping 接続先IPアドレス");
if (result.Contains(ping送信成功を示す特定の文字列)) {return 1;} ・・・★1.ここには来る
else {return 0;}
}

◆/* @brief タスクB:ネットワーク越しのフォルダ間コピーを行う */
private Task TaskB()
{
return Task.Factory.StartNew(() => {
CCopy copy = new CCopy();
while (true) {
if (copy.CopyFolder(m_CTSTaskB).Result == 1) {// コピー成功と判定}
else {// 失敗と判定}
Task.Delay(500, m_CTSTaskB.Token);
}
}, m_CTSTaskB.Token);
}

------------------------- コピークラス:CCopyのメンバ関数 -------------------------

◆/* @brief ネットワーク越しのフォルダ間コピーを行う */
public async Task<int> CopyFolder(CancellationTokenSource cts)
{
CCommon common = new CCommon();
string result = await common.ExeCommandTask(cts, "copy コピー元フォルダ コピー先フォルダ");
if (result.Contains(copy成功を示す特定の文字列)) {return 1;} ・・・★2.ここには来ない
else {return 0;}
}

------------------------- 共通クラス:CCommonのメンバ関数 -------------------------

◆/* @brief コマンドをプロセスで実行するタスク */
public Task<string> ExeCommandTask(CancellationTokenSource cts, string command)
{
return Task.Factory.StartNew(() => {
// コマンドをプロセスで実行する際の設定
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "cmd";
process.StartInfo.Arguments = "/c " + command;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;

try {
// コマンドをOSのプロセスで実行し、1秒ごとに実行完了待ちを行い、同時にタスクキャンセル要求が
// ないか確認する
// 実行完了すれば実行結果をresultに得て、プロセスをクローズする
process.Start();
string result = process.StandardOutput.ReadToEnd();

while (true) {
process.WaitForExit(1000);
if (process.HasExited) {break;}
cts.Token.ThrowIfCancellationRequested();
}
process.Close();
return result;
}

// タスクキャンセル要求があった際に実行中のプロセスがある場合は強制終了する
catch (OperationCanceledException) {
if (!process.HasExited) {process.Kill();}
return "";
}
}, cts.Token, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
}

###補足情報(言語/FW/ツール等のバージョンなど)
C#,Visual Studio2015

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

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

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

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

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

tamoto

2016/08/23 02:49

[該当のソースコード] ですが、GetIsConnect()がTask<int>を返しているのに == 0 で比較されていたり、 async void の CopyFolder() に return 0 を記述していたりと、根本的にコンパイルが通るコードになっていないようです。このままでは設計意図が掴めないので、修正をお願いします。
matsu1

2016/08/23 04:14

すみません、コードが誤っておりましたので修正しておきました。 こちらに記載したコードは実際の開発コードを必要最低限簡易化したものですが、現象が再現しない(★2にくる)ので、見直します。 お手数ですが、のちほどよろしくお願い致します。
matsu1

2016/08/23 08:08

調査しておりましたが、GUI周りのコードに問題があり、それが原因で★2に来ないことがわかりました。上記記載のコードは問題ないかと思われます。 近日中に本質問の削除依頼をします。お手数をおかけしました。
guest

回答1

0

自己解決

調査しておりましたが、GUI周りのコードに問題があり、それが原因で★2に来ないことがわかりました。上記記載のコードは問題ないかと思われますので自己解決とします。

投稿2016/08/24 01:44

matsu1

総合スコア19

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問