我们今天在课堂上学习多线程,我们遇到了一个非常奇怪的错误。在我们的新线程中执行for循环时,for循环的上限不断传递。该线程被杀死,但随后会出现另一个值并结束另一个线程。
出于调试错误的目的,我将上限更改为90以避免进度条上的OutOfRange异常。
在将计数器输出到进度条并更新进度条的同时,我在输出窗口中得到了这个。
如果我在进度条(pbLoad.Value = i;
)上注释了更新,我在输出窗口中得到了这个
我尝试将循环更改为i<101
,并尝试移动到i++
所在的位置,但没有区别
编辑:这来自BeginInvoke
。当我将其切换到Invoke
时,它可以工作,但是当我尝试使用取消按钮时,我将陷入僵局。
以下是代码:
public partial class Form1 : Form
{
Thread backgroundThread;
bool stopExecution = false;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
stopExecution = false;
btnStart.Enabled = false;
backgroundThread = new Thread(DoDomethingThatTakesAWhile);
backgroundThread.Start();
}
private void DoDomethingThatTakesAWhile()
{
for (int i = 0; i <= 100; i++)
{
if (!stopExecution)
{
Thread.Sleep(100);
if (pbLoad.InvokeRequired)
{
MethodInvoker myMethod
= new MethodInvoker(
delegate
{
if (!stopExecution)
{
pbLoad.Value = i;
Debug.WriteLine(i); //i to output window
}
});
pbLoad.BeginInvoke(myMethod);
}
else
{
pbLoad.Value = i;
}
}
else
{
break;
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
//backgroundThread.Abort();
stopExecution = true;
backgroundThread.Join();
pbLoad.Value = 0;
btnStart.Enabled = true;
}
}
答案 0 :(得分:1)
您正在使用BeginInvoke
明确开启比赛的可能性。我建议同步调用。
此外,您正在捕获i
,而不是其值。这很生气,只是因为你正在睡觉而偶然起作用。
任何一项更改都可以解决问题。做他们两个。
如果可以的话,废除这种低级别的同步使用并使用async / await。
答案 1 :(得分:1)
当您致电MethodInvoke
时,此时不会发生,但某段时间。
在您的方案中,您有可能发生以下情况:
i
变为101)i
并阅读101。要修复它,您可以复制i
(通过将其作为参数传递给调用的方法):
pbLoad.BeginInvoke(new Action<int>(a =>
{
if (!stopExecution)
{
pbLoad.Value = a;
Debug.WriteLine(a); //a to output window
}
}), new object[] { i });
P.S:您不需要检查InvokeRequired
,除非您打算直接调用DoDomethingThatTakesAWhile
方法,我认为并非如此。