C# .NET中如何判断CMD进程执行完成?Robocopy事件异常求助
问题原因及解决办法
核心问题1:未启用进程事件触发开关
Process对象默认不会触发Exited事件,因为EnableRaisingEvents属性默认是false。必须手动开启这个开关,否则即使进程退出,也不会触发绑定的事件方法。
核心问题2:线程可见性隐患
AllCopyComplete是普通布尔变量,Exited事件在后台线程中修改它时,主线程的while循环可能因为CPU缓存优化无法及时感知到变量值的变化,导致循环无法退出。
优化建议:无需通过CMD启动Robocopy
直接启动robocopy.exe进程即可,绕开CMD能更直接地监控Robocopy的状态,还能避免额外的进程开销。
修正后的基础版本代码
// 用volatile修饰,保证多线程下变量的可见性 private volatile bool AllCopyComplete = false; public void CopyAll() { Log.Info("Performing initial copy of files..."); string robocopyCommandAll = "/c robocopy <SOURCE> <DEST> /E & exit"; AllCopyProcess = new Process(); AllCopyProcess.StartInfo = new ProcessStartInfo("CMD.exe", robocopyCommandAll); // 关键:开启事件触发开关 AllCopyProcess.EnableRaisingEvents = true; AllCopyProcess.Exited += AllProcessExited; AllCopyProcess.Start(); while (!AllCopyComplete) { Log.Info("Waiting (initial copy)..."); Thread.Sleep(500); } } private void AllProcessExited(Object sender, EventArgs e) { AllCopyComplete = true; Log.Info("All files updated"); }
更高效的进阶版本(直接启动Robocopy)
// 用信号量替代循环Sleep,更高效可靠 private ManualResetEventSlim copyCompletedSignal = new ManualResetEventSlim(false); public void CopyAll() { Log.Info("Performing initial copy of files..."); AllCopyProcess = new Process(); // 直接启动robocopy.exe,无需通过CMD中转 AllCopyProcess.StartInfo = new ProcessStartInfo("robocopy.exe", "<SOURCE> <DEST> /E") { CreateNoWindow = true, // 可选:避免弹出命令行窗口 UseShellExecute = false // 若需要重定向输出则必须设为false }; AllCopyProcess.EnableRaisingEvents = true; AllCopyProcess.Exited += (sender, e) => { var process = (Process)sender; copyCompletedSignal.Set(); // Robocopy退出码有特殊含义:0=无文件复制,1=复制成功,2=存在文件差异等 Log.Info($"All files updated. Robocopy exit code: {process.ExitCode}"); }; AllCopyProcess.Start(); // 等待信号量触发,替代低效的Sleep循环 copyCompletedSignal.Wait(); copyCompletedSignal.Dispose(); }
内容的提问来源于stack exchange,提问作者Inglonias
相关产品推荐
相关产品推荐

