运行另一个没有GUI冻结的进程

时间:2010-03-09 02:22:58

标签: c# multithreading

我无法在运行(并等待)外部进程时让我的GUI出现并且不会冻结。在这种情况下,drivers.exe是一个非常简单的程序,用户只需单击“确定”即可。因此,每当我单击“确定”时,它就会退出。我正在尝试简单地使我的状态条计数数字(非常快)当drivers.exe正在执行时。但实际上,在drivers.exe退出之前,我的GUI根本不会出现。

private void run_drivers()
        {
            Console.WriteLine("Start Driver");
            int driver_timeout_in_minutes = 20;
            System.Diagnostics.Process driverproc = System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "drivers.exe");
            driverproc.WaitForExit(driver_timeout_in_minutes * 1000 * 60);   //uses milliseconds, we must convert
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ThreadStart worker = new ThreadStart(run_drivers);
            Console.WriteLine("Main - Creating worker thread");
            toolStripStatusLabel1.Text = "hi";
            Thread t = new Thread(worker);
            t.IsBackground = true;
            t.Start();
            Console.WriteLine("Main - Have requested the start of worker thread");

            int i = 0;
            while (t.IsAlive)
            {
                i++;
                toolStripStatusLabel1.Text = i.ToString();
            }
            Console.WriteLine("Dead");
        }

4 个答案:

答案 0 :(得分:3)

您应该查看BackgroundWorker,因为它会为您完成所有线程

答案 1 :(得分:2)

您的表单在drivers.exe运行之前未显示的原因是您正在Form.Load内运行drivers.exe。 Form.Load在显示表单之前发生。请尝试在Form.Shown中运行drivers.exe。

此外,while(t.IsAlive)将在技术上阻止您的UI线程。如果这不是你想要的,它应该从主线程移开。您可能还希望在设置文本后调用toolStripStatusLabel1.Refresh()强制标签刷新。

答案 2 :(得分:0)

不要在GUI线程上放置任何循环。它会冻结你的申请。循环必须在后台线程上,后台线程应通过toolStripStatusLabel1方法更新Invoke

看这个例子。未经测试。也许它甚至可能就像这样......

    private void run_drivers()
    {
        Console.WriteLine("Start Driver");
        int driver_timeout_in_minutes = 20;
        System.Diagnostics.Process driverproc = System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "drivers.exe");
        int i = 0;
        var action = new Action<int>(x => {  toolStripStatusLabel1.Text = i.ToString(); })
        while (!driverproc.HasExited)
        {
            i++;
            toolStripStatusLabel1.Invoke(action);
        }

        Console.WriteLine("Dead");
        // start another thread here...
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        ThreadStart worker = new ThreadStart(run_drivers);
        Console.WriteLine("Main - Creating worker thread");
        toolStripStatusLabel1.Text = "hi";
        Thread t = new Thread(worker);
        t.IsBackground = true;
        t.Start();
        Console.WriteLine("Main - Have requested the start of worker thread");
    }

答案 3 :(得分:0)

在保留当前代码结构的同时,您可以使用的一种解决方案是在timer线程上定期更新UI,在线程完成时停止计时器。这样做,您将从循环更改为事件驱动设计,并且您将为UI线程提供时间来绘制表单。

// create a System.Windows.Forms.Timer through the designer or in code.
// give it a short interval if you want the counter to increment quickly.

int counter;

private void Form1_Load(object sender, EventArgs e)
{
    ...
    t.Start();
    counter = 0;
    timer.Start();
    ....
}

private void timer_Tick(object sender, EventArgs e)
{
   if (t.IsAlive)
   {
       counter++;
       toolStripStatusLabel1.Text = counter.ToString(); 
   }
   else
   {
      timer.Stop();
   }
}

(未测试的)