我对我遇到的跨线程访问的情况感到困惑。下面是我正在尝试做的事情:
主UI线程-菜单项单击“我创建后台工作线程并异步运行”
private void actionSubMenuItem_Click(object sender, EventArgs e)
{
ToolStripMenuItem itemSelected = (ToolStripMenuItem)sender;
ExecuteTheActionSelected(itemSelected.Text);
}
方法ExecuteTheActionSelected
如下:
private void ExecuteTheActionSelected(string actionSelected)
{
BackgroundWorker localBackgroundWorker = new BackgroundWorker();
localBackgroundWorker.DoWork += new DoWorkEventHandler(localBackgroundWorker_DoWork);
localBackgroundWorker.RunWorkerAsync(SynchronizationContext.Current);
}
localBackgroundWorker_DoWork
具有:
ActionExecutionHelper actionExecutioner = new ActionExecutionHelper()
actionExecutioner.Execute();
该类中的Execute
方法具有方法调用程序,该方法调用程序实际上调用UI线程中的事件处理程序:
public void Execute()
{
// ---- CODE -----
new MethodInvoker(ReadStdOut).BeginInvoke(null, null);
}
protected virtual void ReadStdOut()
{
string str;
while ((str = executionProcess.StandardOutput.ReadLine()) != null)
{
object sender = new object();
DataReceivedEventArgs e = new DataReceivedEventArgs(str);
outputDataReceived.Invoke(sender, e);
//This delegate invokes UI event handler
}
}
UI事件处理程序如下所示:
private void executionProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (_dwExecuteAction != null)
{
_dwExecuteAction.ShowDataInExecutionWindow(e.Text);
}
}
现在又出现了螺纹错扣问题:
public void ShowDataInExecutionWindow(string message)
{
if (rchtxtExecutionResults.InvokeRequired)
{
rchtxtExecutionResults.Invoke(new ShowDataExecutionDelegate(ShowDataInExecutionWindow), message);
}
else
{
this.rchtxtExecutionResults.AppendText(message + Environment.NewLine);
}
}
这里Invoke不阻塞UI,而BeginInvoke阻塞。请帮助我理解这个场景,因为我很困惑。
1条答案
按热度按时间lvmkulzt1#
是的,这是正常的。Invoke()的好处是它 * 阻塞 * 工作线程。当你使用BeginInvoke()时,线程保持监控,并以高于UI线程处理的速率发出调用请求。这取决于你要求UI线程做什么,但在每秒1000次调用时,它开始成为一个问题。
在这种情况下,UI线程停止响应,它不断地发现另一个调用请求,同时它泵送消息循环,不再做它的常规任务。输入和绘制请求不再得到处理。
问题的明显根源在于从流程中检索到的输出的 * 每一行 * 上的调用请求。它只是生成它们太快了。您需要通过降低调用的速率来解决这个问题。对此有一个简单的规则,您只是试图让一个人忙碌起来,调用超过每秒25次会使你产生的任何东西都变得模糊不清。2因此,缓冲这些行并测量自上一次调用以来所经过的时间。
还要注意的是,使用Invoke()是一个简单的解决方案,但并不能保证它一定能工作。这是一个 * 竞争 *,工作线程可能总是在主线程重新进入消息循环并阅读下一条消息之前调用下一个Invoke()。在这种情况下,您仍然会遇到完全相同的问题。