0

我有一个位于任务栏区域的 Winforms 应用程序。将打开一个用于记录输出的窗口。

现在,在我的组件中(仍然在 UI 线程上)我需要调用一个运行 5-15 分钟并生成文件的外部进程。我需要等待进程退出并使用这些文件。

因为我希望我的 UI 具有响应性(移动窗口等),所以我实现了一个代理并使用 BeginInvoke/EndInvoke 调用该过程:

private delegate int BeginCallDelegate( int port, int baud, int timeout, Job job );
private BeginCallDelegate del = null;

public IAsyncResult BeginCall( int port, int baud, int timeout, Job job )
{
    del = new BeginCallDelegate( Call );
    IAsyncResult iar = del.BeginInvoke( port, baud, timeout, job, null, null );
    return iar;
}

在调用代码中,我使用 WaitOne() 轮询 IAsyncResult 但请注意,如果未冻结,UI 将非常无响应

IAsyncResult a = agent.BeginCall(...); //BeginInvoke
while ( !a.IsCompleted )
{
    iar.AsyncWaitHandle.WaitOne( 250 );
    //writing something to a textbox works here, but overall responsiveness is weak
}

agent.EndCall( iar ); //EndInvoke

VS 告诉我外部进程是在工作线程上启动的,但为什么这对我的 UI 响应没有帮助?它不应该阻塞调用线程

这是启动该过程的代码:

ProcessStartInfo psi = new ProcessStartInfo();

psi.FileName = "app.exe";
psi.Arguments = String.Format( "blah blah", port, baud, timeout, job.FullName );

psi.CreateNoWindow = false;
psi.ErrorDialog = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;

process.StartInfo = psi;

if ( !process.Start() )
    throw new Exception( "The process cannot start." );

process.WaitForExit( job.Timeout );

提示:为了测试,外部 app.exe 是一个虚拟应用程序,除了 Thread.Sleep(60000) 之外什么都不做。CPU 负载为 3%。

另一个问题:如果不使用 Begin/EndInvoke,我将如何以“TPL 方式”执行此操作?

4

2 回答 2

1

尝试在您的主线程中执行此操作:

ProcessStartInfo psi = new ProcessStartInfo();
Thread processStarter = new Thread(delegate()
{
psi.FileName = "app.exe";
psi.Arguments = String.Format( "blah blah", port, baud, timeout, job.FullName );
psi.CreateNoWindow = false;
psi.ErrorDialog = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo = psi;
process.Start();
process.WaitForExit( job.Timeout );
//call methods that deal with the files here
});
processStarter.IsBackground = true;
processStarter.Start();
于 2013-03-14T23:16:57.383 回答
0

您的代码异步启动一个方法,但随后在繁忙的等待循环中阻塞,检查 IsComplete 标志。这不是使用代表的正确方法。

您应该将回调函数传递给 BeginInvoke,而不是忙于等待,该回调函数将在委托完成时调用。这已经包含在文档中。勾选MSDN 的“异步调用同步方法”中的“异步调用完成时执行回调方法” 。

在你的情况下,你必须写:

del.BeginInvoke( port, baud, timeout, job, new AsyncCallBack(MyMethod), null );

其中 MyMethod 是将处理调用结果的方法。

于 2013-03-15T11:54:23.353 回答