簡體   English   中英

從調用線程異步執行的方法中的多個進程

[英]Multiple processes in method executed asynchronously from calling thread

假設我有多個(例如兩個)進程要順序但異步運行,我該如何去做? 請參見下面的代碼段:

public virtual Task<bool> ExecuteAsync()
{
    var tcs = new TaskCompletionSource<bool>();
    string exe1 = Spec.GetExecutablePath1();
    string exe2 = Spec.GetExecutablePath2();
    string args1 = string.Format("--input1={0} --input2={1}", Input1, Input2);
    string args2 = string.Format("--input1={0} --input2={1}", Input1, Input2);

    try
    {
        var process1 = new Process
        {
            EnableRaisingEvents = true,
            StartInfo =
            {
                UseShellExecute = false,
                FileName = exe1,
                Arguments = args1,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                WorkingDir = CaseDir
            }
        };
        var process2 = new Process
        {
            EnableRaisingEvents = true,
            StartInfo =
            {
                UseShellExecute = false,
                FileName = exe2,
                Arguments = args2,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                WorkingDir = CaseDir
            }
        };
        process1.Exited += (sender, arguments) =>
        {
            if (process1.ExitCode != 0)
            {
                string errorMessage = process1.StandardError.ReadToEndAsync();
                tcs.SetResult(false);
                tcs.SetException(new InvalidOperationException("The process1 did not exit correctly. Error message: " + errorMessage));
            }
            else
            {
                File.WriteAllText(LogFile, process1.StandardOutput.ReadToEnd());
                tcs.SetResult(true);
            }
            process1.Dispose();
        };
        process1.Start();

        process2.Exited += (sender, arguments) =>
        {
            if (process2.ExitCode != 0)
            {
                string errorMessage = process2.StandardError.ReadToEndAsync();
                tcs.SetResult(false);
                tcs.SetException(new InvalidOperationException("The process2 did not exit correctly. Error message: " + errorMessage));
            }
            else
            {
                File.WriteAllText(LogFile, process2.StandardOutput.ReadToEnd());
                tcs.SetResult(true);
            }
            process2.Dispose();
        };
        process2.Start();
    }
    catch (Exception e)
    {
        Logger.InfoOutputWindow(e.Message);
        tcs.SetResult(false);
        return tcs.Task;
    }

    return tcs.Task;
}

}

預先感謝您的想法。

編輯 #1:

當我如上所述運行代碼時,成功完成第一個過程后,它將失敗並顯示以下錯誤:

"System.InvalidOperationException; An attempt was made to transition a task to a final state when it had already completed".

當我只用第一個進程運行代碼(刪除與另一個進程有關的所有代碼)時,它運行正常。

您看到的錯誤與這兩個過程無關。 這是由於多次設置TaskCompletionSource的SetResult方法引起的。 您不能給同一任務兩個不同的結果。

有一些重要的變化:

  1. 不要僅僅因為第一個過程成功就將任務完成設置為true。 您希望它等待第二個過程完成才能確定它是否真的成功。 刪除對process1.Exited中的'tsc.SetResult(true)'的調用。
  2. 您只應在process1完成后啟動process2(您說過希望它們是同步的。為此,請在process1的Exited處理程序中啟動process2。此外,我假設如果process1失敗,則您不想啟動process2。
  3. 將process2.Exited處理程序移至調用process1.Start()的上方。 這只是避免了在設置process2的Exited處理程序之前,process1和process2真的很快完成時的爭用條件。

這未經測試,但是您的代碼最終應該看起來像這樣:

public virtual Task<bool> ExecuteAsync()
{
    var tcs = new TaskCompletionSource<bool>();
    string exe1 = Spec.GetExecutablePath1();
    string exe2 = Spec.GetExecutablePath2();
    string args1 = string.Format("--input1={0} --input2={1}", Input1, Input2);
    string args2 = string.Format("--input1={0} --input2={1}", Input1, Input2);

    try
    {
        var process1 = new Process
        {
            EnableRaisingEvents = true,
            StartInfo =
            {
                UseShellExecute = false,
                FileName = exe1,
                Arguments = args1,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                WorkingDir = CaseDir
            }
        };
        var process2 = new Process
        {
            EnableRaisingEvents = true,
            StartInfo =
            {
                UseShellExecute = false,
                FileName = exe2,
                Arguments = args2,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                WorkingDir = CaseDir
            }
        };
        process1.Exited += (sender, arguments) =>
        {
            if (process1.ExitCode != 0)
            {
                string errorMessage = process1.StandardError.ReadToEndAsync();
                tcs.SetResult(false);
                tcs.SetException(new InvalidOperationException("The process1 did not exit correctly. Error message: " + errorMessage));
            }
            else
            {
                File.WriteAllText(LogFile, process1.StandardOutput.ReadToEnd());
                process2.Start();
            }
            process1.Dispose();
        };

        process2.Exited += (sender, arguments) =>
        {
            if (process2.ExitCode != 0)
            {
                string errorMessage = process2.StandardError.ReadToEndAsync();
                tcs.SetResult(false);
                tcs.SetException(new InvalidOperationException("The process2 did not exit correctly. Error message: " + errorMessage));
            }
            else
            {
                File.WriteAllText(LogFile, process2.StandardOutput.ReadToEnd());
                tcs.SetResult(true);
            }
            process2.Dispose();
        };

        process1.Start();
    }
    catch (Exception e)
    {
        Logger.InfoOutputWindow(e.Message);
        tcs.SetResult(false);
        return tcs.Task;
    }

    return tcs.Task;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM