Unity中调用外部EXE时WaitForExit阻塞主程序的问题咨询
Hey there! I totally get your frustration—you’re trying to launch an external EXE in Unity that relies on microphone input, but using WaitForExit() locks up your Unity app until the EXE closes. That’s no good when you need Unity to keep handling updates, UI, or other tasks in the background. Let’s break down how to solve this without blocking the main thread.
Why WaitForExit() Causes the Freeze
Unity runs almost all critical operations (like rendering, input handling, and MonoBehaviour updates) on its main thread. When you call WaitForExit(), it blocks this thread entirely until the external process finishes. That’s why your app becomes unresponsive—Unity can’t do anything else until the EXE closes.
Solution 1: Use the Process.Exited Event
This approach lets you listen for when the EXE exits without blocking the main thread. We’ll enable event raising for the process and hook into its Exited callback.
Here’s a ready-to-use script example:
using UnityEngine; using System.Diagnostics; public class ExternalExeRunner : MonoBehaviour { // Call this method to start your EXE (e.g., from a UI button click) public void LaunchExternalExe() { var process = new Process(); process.StartInfo.FileName = "path/to/your/exe.exe"; // Add any other StartInfo config you need (working directory, arguments, etc.) process.StartInfo.UseShellExecute = false; // Critical: Enable event raising so we get notified when the EXE exits process.EnableRaisingEvents = true; // Hook up the exit callback process.Exited += OnExeExited; // Start the process—Unity's main thread won't block here! process.Start(); } private void OnExeExited(object sender, System.EventArgs e) { var finishedProcess = sender as Process; if (finishedProcess == null) return; // Get the exit code if you need it int exitCode = finishedProcess.ExitCode; // Important: Unity API calls (like Debug.Log or UI updates) must run on the main thread! // Use Invoke to jump back to the main thread for these operations Invoke(() => { Debug.Log($"External EXE exited with code: {exitCode}"); // Add your post-exit logic here (e.g., update UI, trigger game events) }, 0); // Clean up process resources to avoid leaks finishedProcess.Dispose(); } // Optional: Clean up if the MonoBehaviour is destroyed before the EXE exits private void OnDestroy() { // If you're keeping a reference to the process, check if it's still running and close it // (You'd need to store the process instance as a class variable for this) } }
Key Notes for This Method:
- The
Exitedcallback runs on a background thread, never call Unity API methods directly here—always useInvoke()or a main thread dispatcher to handle Unity-specific logic. - Make sure your EXE has proper access to the microphone. If Unity is already using the mic, you might need to adjust microphone permissions or disable Unity’s mic usage temporarily while the EXE runs.
Solution 2: Use Async/Await with Background Threading
If you prefer working with async patterns, you can offload the WaitForExit() call to a background thread using Task.Run(), then await it without blocking Unity’s main thread.
Here’s how that looks:
using UnityEngine; using System.Diagnostics; using System.Threading.Tasks; public class AsyncExeRunner : MonoBehaviour { public async void LaunchExeAsync() { var process = new Process(); process.StartInfo.FileName = "path/to/your/exe.exe"; process.StartInfo.UseShellExecute = false; process.Start(); // Wait for the EXE to exit on a background thread await Task.Run(() => process.WaitForExit()); // After await, we're back on the main thread? Not always—play it safe with Invoke int exitCode = process.ExitCode; Invoke(() => { Debug.Log($"EXE exited with code: {exitCode}"); // Handle post-exit Unity logic here }, 0); process.Dispose(); } }
Why This Works:
Task.Run() moves the blocking WaitForExit() call to a separate thread, so Unity’s main thread stays free to handle updates. The await keyword pauses the async method until the task completes, but doesn’t block the rest of the app.
Important Reminders
- Clean Up Process Resources: Always call
Dispose()on theProcessobject once it’s done to avoid memory leaks. - Microphone Access Conflicts: If both Unity and the EXE need the microphone, you might need to release Unity’s mic capture before launching the EXE, then reinitialize it afterward.
- Error Handling: Add try/catch blocks around process start/exit logic to handle cases where the EXE fails to launch or crashes unexpectedly.
内容的提问来源于stack exchange,提问作者Khaled Gomaa

