好吧,让我们来看看你已经拥有什么。
首先,我看到你这样做了。
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
ThreadStart HUp = new ThreadStart(dothis);
t = new Thread(HUp);
t.Start();
}
虽然这肯定不是最新鲜的东西,但它仍然可以工作。如果你想要一些更新鲜的食材,那么你可以用这个代替。
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
Task.Factory.StartNew(dothis);
}
其次,我看到了这一点。
public void dothis()
{
if (intHour < 23) intHour = intHour += intStep;
lblTimerHour.Text = intHour.ToString("00");
}
这里的问题是您试图从主 UI 线程以外的线程更新 UI 控件。您会看到 UI 控件具有所谓的线程关联性。它们只能从创建它们的线程访问。你所拥有的将导致各种不可预知的问题,甚至包括在时空中撕裂一个整体。
更好的选择是这样做。
public void dothis()
{
while (intHour < 23)
{
intHour = intHour += intStep;
lblTimerHour.Invoke((Action)(
() =>
{
lblTimerHour.Text = intHour.ToString("00");
}));
}
}
我假设你错过了循环,所以我添加了它。虽然我不能说我个人对这种东西有品味,但它更容易下咽。这里真正的问题是工作线程真的没有做很多有用的工作。然后最重要的是,我们必须使用笨拙的编组操作将结果传输回 UI 线程。它不漂亮,但它会起作用。
最后,这让我想到了这一点。
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
t.Abort();
}
您正试图中止一个非常不可取的线程。问题是它在不可预测的时间从线程中抽出控制。该线程可能正在写入数据结构,这会破坏它。这实际上是一个非常糟糕的问题,因为在从调用堆栈上的任何一个帧操作的过程中的任何数据结构都可能处于不一致的状态。这包括您未编写的代码。这就是为什么很难说你这样做可能会或可能不会破坏什么。
您需要考虑的是使用合作取消机制。这包括使用CancellationTokenSource
和CancellationToken
。这是我们将所有内容放在一起后的样子。
private CancellationTokenSource cts = null;
private void btnHUp_MouseDown(object sender, MouseEventArgs e)
{
cts = new CancellationTokenSource();
Task.Factory.StartNew(() => dothis(cts.Token));
}
private void btnHUp_MouseUp(object sender, MouseEventArgs e)
{
cts.Cancel();
}
public void dothis(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
intHour += intStep;
lblTimerHour.Invoke((Action)(
() =>
{
lblTimerHour.Text = intHour.ToString("00");
}));
Thread.Sleep(1000);
}
}
这样做是表明工作线程应该自行正常关闭。这使工作线程有机会在最终自行终止之前进行整理。