C# 异步进程启动并等待它完成
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/611094/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Async process start and wait for it to finish
提问by Bogdan Gavril MSFT
I am new to the thread model in .net. What would you use to:
我是 .net 中线程模型的新手。你会用来做什么:
- start a process that handles a file (process.StartInfo.FileName = fileName;)
- wait for the user to close the process OR abandon the thread after some time
- if the user closed the process, delete the file
- 启动一个处理文件的进程(process.StartInfo.FileName = fileName;)
- 等待用户关闭进程或在一段时间后放弃线程
- 如果用户关闭了进程,删除文件
Starting the process and waiting should be done on a different thread than the main thread, because this operation should not affect the application.
启动进程和等待应该在与主线程不同的线程上完成,因为这个操作不应该影响应用程序。
Example:
例子:
My application produces an html report. The user can right click somewhere and say "View Report" - now I retrieve the report contents in a temporary file and launch the process that handles html files i.e. the default browser. The problem is that I cannot cleanup, i.e. delete the temp file.
我的应用程序生成一个 html 报告。用户可以右键单击某处并说“查看报告” - 现在我在临时文件中检索报告内容并启动处理 html 文件的进程,即默认浏览器。问题是我无法清理,即删除临时文件。
采纳答案by Marc Gravell
"and waiting must be async" - I'm not trying to be funny, but isn't that a contradiction in terms? However, since you are starting a Process
, the Exited
event may help:
“并且等待必须是异步的”-我不是想搞笑,但这不是自相矛盾吗?但是,由于您正在启动Process
,因此该Exited
事件可能会有所帮助:
ProcessStartInfo startInfo = null;
Process process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
process.Exited += delegate {/* clean up*/};
If you want to actually wait (timeout etc), then:
如果您想实际等待(超时等),则:
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout (perhaps process.Kill();)
}
For waiting async, perhaps just use a different thread?
对于等待异步,也许只是使用不同的线程?
ThreadPool.QueueUserWorkItem(delegate {
Process process = Process.Start(startInfo);
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout
}
});
回答by JaredPar
Try the following code.
试试下面的代码。
public void KickOffProcess(string filePath) {
var proc = Process.Start(filePath);
ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc);
}
private void WaitForProc(object obj) {
var proc = (Process)obj;
proc.WaitForExit();
// Do the file deletion here
}
回答by Chris Holmes
I would probably not use a separate process for opening a file. Instead, I'd probably utilize a background thread (if I thought the operation was going to take a long time and possible block the UI thread).
我可能不会使用单独的过程来打开文件。相反,我可能会使用后台线程(如果我认为该操作将花费很长时间并且可能会阻塞 UI 线程)。
private delegate void FileOpenDelegate(string filename);
public void OpenFile(string filename)
{
FileOpenDelegate fileOpenDelegate = OpenFileAsync;
AsyncCallback callback = AsyncCompleteMethod;
fileOpenDelegate.BeginInvoke(filename, callback, state);
}
private void OpenFileAsync(string filename)
{
// file opening code here, and then do whatever with the file
}
Of course, this is not a good working example (it returns nothing) and I haven't shown how the UI gets updated (you have to use BeginInvoke at the UI level because a background thread cannot update the UI thread). But this approach is generally how I go about handling asynchronous operations in .Net.
当然,这不是一个好的工作示例(它不返回任何内容)并且我没有展示 UI 如何更新(您必须在 UI 级别使用 BeginInvoke,因为后台线程无法更新 UI 线程)。但是这种方法通常是我在 .Net 中处理异步操作的方式。
回答by Pablo Retyk
You can use the Exited
event in Process class
您可以Exited
在 Process 类中使用该事件
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "notepad.exe";
Process process = Process.Start(info);
process.Exited += new EventHandler(process_Exited);
Console.Read();
and in that event you can handle the operations you mentioned
在这种情况下,您可以处理您提到的操作
回答by Chris Gillum
Adding an advanced alternative to this old question. If you want to wait for a process to exit without blocking any thread and still support timeouts, try the following:
为这个老问题添加一个高级替代方案。如果您想等待进程退出而不阻塞任何线程并仍然支持超时,请尝试以下操作:
public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
{
ManualResetEvent processWaitObject = new ManualResetEvent(false);
processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredProcessWaitHandle = null;
registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
processWaitObject,
delegate(object state, bool timedOut)
{
if (!timedOut)
{
registeredProcessWaitHandle.Unregister(null);
}
processWaitObject.Dispose();
tcs.SetResult(!timedOut);
},
null /* state */,
timeout,
true /* executeOnlyOnce */);
return tcs.Task;
}
Again, the advantage to this approach compared to the accepted answer is that you're not blocking any threads, which reduces the overhead of your app.
同样,与公认的答案相比,这种方法的优势在于您不会阻塞任何线程,从而减少了应用程序的开销。