在方法多个程序同时调用线程异步执行 [英] Multiple processes in method executed asynchronously from calling thread

查看:402
本文介绍了在方法多个程序同时调用线程异步执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有多重(例如,二),我想按顺序运行,但不同步,我怎么去这样做的过程?请参见下面的代码片段:

Suppose I have multiple (say, two) processes that I want to run sequentially but asynchronously, how do I go about doing this? See snippet below:

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

当我运行code如上图所示,它不能低于在成功完成第一道工序错误:

When I run the code as shown above it fails with the error below after successfully completing the first process:

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

当我运行code只有第一个进程(删除与其他所有code),它运行正常。

When I run the code with just the first process (delete all code pertaining to the other), it runs OK.

推荐答案

您看到的错误是毫无关系的两个过程。它通过设置TaskCompletionSource多次的方法的setResult造成的。你不能给同一个任务两种不同的结果。

The error you're seeing is unrelated to the two processes. It's caused by setting the SetResult method of the TaskCompletionSource multiple times. You can't give the same task two different results.

有几个重要的变化:


  1. 请不要在任务完成设置为true,只是因为第一个进程成功。你想让它要等到第二个过程是做决定,如果它真的成功了。在process1.Exited删除调用'tsc.SetResult(真)。

  2. 您应该只启动过程2过程1完成后(你说你想他们是同步的。要做到这一点,在过程1的退出的处理程序启动过程2。另外,我想你不想启动过程2,如果过程1失败

  3. 将在process2.Exited处理多达上面,你叫process1.Start()。这只是避免了竞争条件时,过程1和过程2完整的真的很快的过程2已退出处理程序设置之前。

这是未经测试,但你的code应该结束了寻找这样的:

This is untested, but your code should end up looking something like this:

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;
}

这篇关于在方法多个程序同时调用线程异步执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆