首页 > 解决方案 > 如何使用 C# 使用线程启动进程

问题描述

问题:线程在启动抛出异常的进程时被放弃。

编辑

我正在重复这个问题以及我想要实现的目标,如何从线程启动进程。

背景故事

我需要运行 exe 的进程,例如 imagemagick、libreoffice。我正在尝试转换许多文件,然后将它们的结果附加到文件中。稍后对状态文件进行进一步处理。

我不擅长线程,我一直在参考 stackoverflow 上的一些帖子,例如this

我正在尝试做这样的事情:

foreach (Preset pr in listOfPreset)
        {
            ConvertRipper cRipper = new ConvertRipper(pr);
            ThreadStart job = (new ThreadStart(()=> cRipper.Ripper()));
            Thread th = new Thread(job);
            th.Start();
        }


public void Ripper()
    {
        //create the folders before converting
        if (!Directory.Exists(preset.OutputFilePath))
            Directory.CreateDirectory(preset.OutputFilePath);

        Document document = CreateDocument(preset);
        ProcessResult pr = v3Engine.Convert(Const.IMAGEMAGICK, v3Engine.ConvertImages(document));

        if (pr.ExitCode == 0)
        {
            //write status to a file the xml status
        }
    }

现在在 Ripper 方法的某个地方我确实有一个开始的进程,我基本上调用一个 windows exe 来转换一些文件

转换方法

    Process proc = new Process();
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.RedirectStandardError = true;
    proc.StartInfo.UseShellExecute = false;

    proc.StartInfo.Arguments = arguments;
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

    proc.ErrorDataReceived += (sender, args) => error.Append(args.Data);
    proc.OutputDataReceived += (sender, args) => output.Append(args.Data);

    proc.Start(); *loc1*

    proc.BeginOutputReadLine();
    proc.BeginErrorReadLine();
    proc.WaitForExit();

    ProcessResult pr = new ProcessResult
    {
          StandardOutput = output.ToString(),
          ErrorOutput = error.ToString(),
          ExitCode = proc.ExitCode
    };

     proc.Close();

     return pr;`

编辑

System.Diagnostics.ProcessStartInfo.set_RedirectStandardError(Boolean value)\r\n 在 C:\Users\dev\source\repos\Converstion\Converstion\ 中 Conversion.Converter.AbstractConvertor.Convert(String executor, String arguments) 的堆栈跟踪"转换器\AbstractConvertor.cs:第 54 行"

*异常状态:**

无法计算表达式,因为代码已优化或本机框架位于调用堆栈顶部。

在我的过程完成后。我想将进程状态写入文件。

示例中,我不明白它如何适合我的情况。因为,我已经在方法 Ripper 上使用了它,该方法间接地将 Process.start() 包含在 Convert 方法中;

PS:我读过诸如“当然,一个进程在一个新进程(一个完全独立的线程束)中启动的评论,所以在一个线程上启动它是完全没有意义的。”

@Downvoter,您能否分享一下我如何根据您的喜好更改此问题。

我觉得我的场景需要它。如果没有,你能建议我还能做什么。

任何提示将不胜感激。如果您对我的测试有任何疑问,请告诉我。

标签: c#multithreading

解决方案


这是优雅而酷的解决方案:使用任务而不启动线程。

请对此持保留态度,这有点乏味,我删除了所有与理解该想法无关的代码:

首先我们有以下扩展类,它是创建执行进程而不启动线程的任务的关键:

public static class Extensions
{
    public static Task ExecuteAsync(this Process process)
    {
        var tcs = new TaskCompletionSource<bool>();
        process.Exited += (sender, eventArgs) =>
        {
            tcs.TrySetResult(true);
        };
        try
        {
            process.Start();
        }
        catch (Exception ex)
        {
            tcs.TrySetException(ex);
        }
        return tcs.Task;
    }
}

然后我们有了Convert方法,它现在是一个async函数:

static async Task<ProcessResult> Convert()
{
    var proces = new Process();
    // Configure process
    // .......
    // End configure process

    await proces.ExecuteAsync();

    return new ProcessResult
    {
        ExitCode = proces.ExitCode,
        // Set other properties
    };
}

Ripper也是async

static async Task Ripper()
{
    // prepare convert arguments
   ProcessResult result = await Convert();
   // do something with the result
}

最后是主要方法:

var tasks = new List<Task>();
foreach (var item in list)
{
    tasks.Add(Ripper());
}
Task.WaitAll(tasks.ToArray());

希望能帮助到你。


推荐阅读