c# - 如何使用 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,您能否分享一下我如何根据您的喜好更改此问题。
我觉得我的场景需要它。如果没有,你能建议我还能做什么。
任何提示将不胜感激。如果您对我的测试有任何疑问,请告诉我。
解决方案
这是优雅而酷的解决方案:使用任务而不启动线程。
请对此持保留态度,这有点乏味,我删除了所有与理解该想法无关的代码:
首先我们有以下扩展类,它是创建执行进程而不启动线程的任务的关键:
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());
希望能帮助到你。
推荐阅读
- amazon-cognito - 'Addlogin' 方法采用什么样的令牌?
- c++ - 无临时变量的 C++20 范围适配器的标准输入
- azure - 如何使用模板将 msi 范围添加到 azure 中的另一个 RG
- spring - 在 localhost 中运行 Spring Boot 应用程序时出错
- python - 使用 Python 从 URL 下载 m3u8
- function - 给定一个库函数,我如何获得它的文件偏移量?
- javascript - 错误类型错误:无法读取未定义的属性“过滤器”。我该如何解决?
- android - android片段中的Razorpay回调不起作用
- php - 如何使用 php mysqli 从存储在单个数据库列中的图像数组中删除和更新单个图像?
- javascript - 使用 React-select 设置多个选定值