【问题标题】:How can I start and wait for an external process?如何启动并等待外部进程?
【发布时间】:2012-03-05 20:05:52
【问题描述】:

我正在尝试启动一个外部进程并等待它处于活动状态,然后再继续执行我的程序。我正在根据进程名称进行搜索,但如果进程名称不是我所期望的,我的实现就会出现问题。

//When Method1 is called, it will load the data and bring a pop up
//as adobe save dialog box (as a save dialog exe in the task bar)
Method1(); 

while (true)
{
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (clsProcess.ProcessName.Contains("AdobeARM"))
        {
            isOpened = true;
        }
    }  

    //Once the pop up from Method 1 comes i call other methods     
    if (isOpened)
    {
        Method2();
        Method3();
        Method4();
        break;
    }
}

如果永远找不到进程,这可能会导致无限循环!处理此问题或替代while 循环的最佳方法是什么?

【问题讨论】:

  • 设置某种限制,可以是尝试次数,也可以是放弃检查前的时间长度。如果你走那条路,你绝对应该在检查之间暂停(正如@M.Babcock 建议的那样。)
  • 这是为了检查它是否正在运行?还是监控并等待它运行?

标签: c# winforms pdf


【解决方案1】:

摆脱这段时间。

它将执行检查,然后如果存在 Adob​​eARM 进程,它将运行您的方法,否则将跳过它们。将 Method1 之后的所有内容放在一个单独的函数中,然后从 System.Threading.Timer 调用该函数。

请注意,根据它在您的应用程序中的使用方式,您可能需要为线程问题添加额外的处理。

private Timer myTimer;

private void DoSomething()
{
    if (myTimer != null)
    {
        myTimer.Dispose();
        myTimer = null;
    }

    Method1();

    myTimer = new Timer(CheckForProcess, null, 100, 100);
}

private void CheckForProcess(object state)
{
    bool isOpened = false;
    foreach (Process clsProcess in Process.GetProcesses())
    {
        if (clsProcess.ProcessName.Contains("AdobeARM"))
        {
            isOpened = true;
            break;
        }
    }

    //Once the pop up from Method 1 comes i call other methods     
    if (isOpened)
    {
        myTimer.Dispose();
        myTimer = null;
        Method2();
        Method3();
        Method4();
    }
}

【讨论】:

  • 即使我尝试过这个,但我认为由于时间问题,这并没有击中 isOpened 标志并调用其他方法。
  • 我进行了编辑。我相信这正是您想要的。
  • 'System.Windows.Forms.Timer' 不包含带有 4 个参数的构造函数,我得到了什么,有什么想法吗?
【解决方案2】:

你说'我正在尝试启动一个外部进程并等待它在继续之前处于活动状态',所以我想你使用:

Process prc = new Process(...);
prc.Start();

如果是,我会打电话给

prc.WaitForInputIdle();

然后继续。
来自 MSDN

WaitForInputIdle - Causes the Process component to wait indefinitely for the associated process to enter an idle state. This overload applies only to processes with a user interface and, therefore, a message loop.

【讨论】:

    【解决方案3】:

    可能只是休息?

    while (true)
    {
    
    
               foreach (Process clsProcess in Process.GetProcesses())
               {
                        if (clsProcess.ProcessName.Contains("AdobeARM"))
                        {
                              isOpened = true;
                        }
               }  
               //Once the pop up from Method 1 comes i call other methods                                  
               if (isOpened)
               {
                 Method2();
                 Method3();
                 Method4();
                 break;
               }
               else
                 break; //BREAK HERE, CAUSE NO PROCESSES of ADOBE...
    }
    

    如果你想一次又一次地想出这个代码,使用Timer,但在这种情况下,显然不要使用更多的while循环。

    【讨论】:

    • 我假设他想在 Adob​​eARM 进程启动时不断监控并做出反应。在这种情况下,他最好完全摆脱“while”而不是使用这个解决方案。
    • 不,休息没有帮助,它运行第一个方法并爆发,并没有击中其他方法。
    • 如果有其他更好的方法,请分享。谢谢。
    • 如果你像这样在第一次迭代中跳出循环,为什么还要有一个while循环呢? OP 正在尝试等待 Adob​​eARM 运行;问题是如果 Adob​​eARM 从未启动(或者启动的程序的进程名称不包含“AdobeARM”),该程序将永远不会放弃。
    • @Sharpeye500:不太清楚那些“其他方法”是什么,抱歉。但我想,你需要使用 Timer 而不要使用 while 循环。在这种情况下,您可以定期检查Adobe 进程是否存在。而且,可能是,在一些滴答声之后,如果Adobe 进程仍然不存在,如果这是您的意图,请退出程序。
    【解决方案4】:

    使用睡眠总是有帮助的

    System.Threading.Thread.Sleep(100); //100ms pause before continuing
    

    如果你已经循环了超过 500 次(50 秒有延迟)你不会找到它并且应该跳出循环,那么有一个计数器或其他东西也可能是有意义的.

    暂停将允许您的屏幕也重新绘制,而不是完全锁定线程。

    【讨论】:

    • 我不能使用 Thred.Sleep 因为方法 1 可能会返回更少的数据(少于 100 条记录或更多数据(超过 5000 条),所以这取决于参数,因此我没有使用睡眠,睡眠将有助于减少数据。
    • @Sharpeye500 - 您的问题不包含有关返回多少记录的任何意外情况,这与您的问题无关......问题(如您所描述的)是“这里的问题是,如果任务管理器 exe 没有类似“AdobeARM”的东西,如果它有其他东西,我的 while 循环将进入无限循环。“是的,它会无限循环,因为你从来没有告诉它停止,它会占用大量的 CPU 周期,除非你告诉它休眠。
    【解决方案5】:

    尝试一个基于某个超时值结束的while循环,而不是while(true):

    //When Method1 is called, it will load the data and bring a pop up
    //as adobe save dialog box (as a save dialog exe in the task bar)
    Method1(); 
    
    //define a "timeout" time one minute from now. (or whatever)
    var timeout = DateTime.Now.AddSeconds(60);
    
    //loop only while the current time has not exceeded the timeout
    while (DateTime.Now < timeout)
    {
        foreach (Process clsProcess in Process.GetProcesses())
        {
            if (clsProcess.ProcessName.Contains("AdobeARM"))
            {
                isOpened = true;
            }
        }  
    
        //Once the pop up from Method 1 comes i call other methods     
        if (isOpened)
        {
            Method2();
            Method3();
            Method4();
            break;
        }
        else
            Thread.Yield(); //gives other threads CPU time; Thread.Sleep() works too.
    }
    
    //If we exit the loop without isOpened being set, we should probably tell someone.
    if(!isOpened) throw new Exception("The operation timed out waiting for AdobeARM.");
    

    【讨论】:

    • +1 让你摆脱困境,因为我会这样做。不过问题是,Thread.YieldDoEvents 基本相同吗?我很确定DoEvents 是撒旦的产物。
    • Thread.Yield() 是代码异味。我不会把它称为 Application.DoEvents() 那样严重。使用 Yield() 或 Sleep() 表示正在等待其他事情发生的“轮询循环”(这正是这个循环),并且通常有更好的解决方案(例如计时器)。我的示例以最少的代码重组为他提供了他需要的东西(一种摆脱他的“while true”构造在特定情况下创建的无限循环的方法)。
    • Timer 可能是整体上更清洁的解决方案,但看起来他在这里的调用是调用其他进程,然后等待该进程启动。如果这种情况永远不会发生,他最终不得不“放弃”,并且知道如何超时的计时器可能会被认为是更大的代码异味(一个事件处理程序对包含它所钩住的事件的单独对象具有密切的紧密耦合知识到?)
    猜你喜欢
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    相关资源
    最近更新 更多