Process.Start 阻塞

问题描述 投票:0回答:7

我正在调用 Process.Start,但它会阻塞当前线程。

pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");

// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
    Trace.TraceError("Unable to run process {0}.");
}

即使进程关闭,代码也不再响应。

但是 Process.Start 真的应该阻塞吗?发生什么事了?

(进程正确启动)


using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

namespace Test
{
    class Test
    {
        [STAThread]
        public static void Main()
        {
            Thread ServerThread = new Thread(AccepterThread);
            ServerThread.Start();

            Console.WriteLine (" ---  Press ENTER to stop service ---");
            while (Console.Read() < 0) { Application.DoEvents(); }

            Console.WriteLine("Done.");
        }

        public static void AccepterThread(object data)
        {
            bool accepted = false;

            while (true) {
                if (accepted == false) {
                    Thread hThread = new Thread(HandlerThread);
                    accepted = true;
                    hThread.Start();
                } else
                    Thread.Sleep(100);
            }
        }

        public static void HandlerThread(object data)
        {
            ProcessStartInfo pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");

            Console.WriteLine("Starting process.");

            // Start process
            Process mProcess = new Process();
            mProcess.StartInfo = pInfo;
            if (mProcess.Start() == false) {
                Console.WriteLine("Unable to run process.");
            }
            Console.WriteLine("Still living...");
        }
    }
}

控制台输出为:

--- 按 ENTER 停止服务 --- 启动过程。


找到了:

[STA线程]

使 Process.Start 阻塞。我读过 STAThread 和多线程,但我无法将这些概念与 Process.Start 行为联系起来。

据我所知,STAThread 是 Windows.Form 必需的。使用 Windows.Form 时如何解决此问题?


地狱新闻:

如果我重建我的应用程序,第一次我运行应用程序时可以正常工作,但是如果我停止调试并再次重新启动 iy,则会出现问题。

在没有调试器的情况下执行应用程序时,不会出现此问题。

c# process blocking sta
7个回答
13
投票

不,

Process.Start
不会等待子进程完成...否则你将无法使用重定向 I/O 等功能。

控制台应用程序示例:

using System;
using System.Diagnostics;

public class Test
{
    static void Main()
    {
        Process p = new Process { 
            StartInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe")
        };
        p.Start();
        Console.WriteLine("See, I'm still running");
    }
}

这会打印“看,我仍在运行”,在我的盒子上没有任何问题 - 它在你的盒子上做什么?


7
投票

创建一个 ProcessStartInfo 并将 UseShellExecute 设置为 false(默认值为 true)。您的代码应为:

pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
pInfo.UseShellExecute = false;

// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
    Trace.TraceError("Unable to run process {0}.");
}

我遇到了同样的问题,并直接从可执行文件启动创建进程的可执行文件解决了该问题。


1
投票

我在 WinForms 应用程序中遇到了与原始海报相同的阻塞行为,因此我创建了下面的控制台应用程序来简化测试此行为。

Jon Skeet 的示例使用记事本,只需几毫秒即可正常加载,因此线程块可能会被忽视。 我试图启动 Excel,这通常需要更长的时间。

using System;
using System.Diagnostics;
using static System.Console;
using System.Threading;

class Program {

    static void Main(string[] args) {

        WriteLine("About to start process...");

        //Toggle which method is commented out:

        //StartWithPath();  //Blocking
        //StartWithInfo();  //Blocking
        StartInNewThread(); //Not blocking

        WriteLine("Process started!");
        Read();
    }

    static void StartWithPath() {
        Process.Start(TestPath);
    }

    static void StartWithInfo() {
        var p = new Process { StartInfo = new ProcessStartInfo(TestPath) };
        p.Start();
    }

    static void StartInNewThread() {
        var t = new Thread(() => StartWithPath());
        t.Start();
    }

    static string TestPath =
        Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
        "\\test.xlsx";
}

StartWithPath
StartWithInfo
的调用会阻止我在控制台应用程序中的线程。 在 Excel 初始屏幕关闭并且主窗口打开之前,我的控制台不会显示“进程已启动”。

enter image description here

StartInNewThread
将立即在控制台上显示两条消息,而 Excel 的启动屏幕仍然打开。


0
投票

我们在启动位于不同域的网络驱动器上的 .bat 脚本时遇到了这个问题(我们有双受信任域)。 我运行了一个远程 C# 调试器,果然 Process.Start() 无限期地阻塞了。

在 Power shell 中以交互方式重复此任务时,会弹出一个安全对话框:

enter image description here

就解决方案而言,这就是我们前进的方向。 完成这项工作的人修改了域 GPO 以实现信任。


0
投票
通过命令提示符启动服务器:

"C:\Program Files (x86)\IIS Express\iisexpress" /path:\Publish /port:8080

这可以访问操作系统树进程的子线程。


0
投票
如果您想启动进程,然后使进程独立于“启动器”/原始调用:

//Calling process using (System.Diagnostics.Process ps = new System.Diagnostics.Process()) { try { ps.StartInfo.WorkingDirectory = @"C:\Apps"; ps.StartInfo.FileName = @"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"; //command ps.StartInfo.Arguments = @"C:\Apps\xyz.accdb"; //argument ps.StartInfo.UseShellExecute = false; ps.StartInfo.RedirectStandardOutput = false; ps.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized; ps.StartInfo.CreateNoWindow = false; //display a windows ps.Start(); } catch (Exception ex) { MessageBox.Show(string.Format("==> Process error <=={0}" + ex.ToString(), Environment.NewLine)); } }
    

0
投票
我也有类似的问题。正在运行的 WPF 应用程序需要检查远程存储上是否存在某个可执行文件、下载它并以提升的权限运行它。初始化进程的应用程序应该关闭,因为它会干扰它的文件。这种方法会阻止执行并且应用程序无法关闭:

ProcessStartInfo processInfo = new ProcessStartInfo { FileName = patcherPath, UseShellExecute = true, Verb = "runas" }; Process.Start(processInfo); Application.Current.Shutdown();
我认为 UAC 与它有关,因为没有它 Process.Start 是一个非阻塞调用。这可能不是最好的方法,但这对我有用:

ProcessStartInfo processInfo = new ProcessStartInfo { FileName = Environment.GetEnvironmentVariable("COMSPEC"), Arguments = $"/c start \"\" \"{PatcherPath}\"", UseShellExecute = true, Verb = "runas", CreateNoWindow = true }; Process.Start(processInfo); Application.Current.Shutdown();
UAC 提示后,调用应用程序将关闭,并且进程似乎可以正确执行。但缺点是它掩盖了我们实际想要启动的内容,因为 UAC 窗口请求提升控制台的权限,而不是目标可执行文件。

© www.soinside.com 2019 - 2024. All rights reserved.