###前提・実現したいこと
お世話になります。
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
回答1件
あなたの回答
tips
プレビュー