我在Visual Studio 2017中使用WinForms在C#中编写程序 任务是Fibonacci数字开始计算程序何时启动(表单加载时)
当我通过文本框输入数字时,已经计算并写入数组。数字显示。
当我输入一个尚未计算的数字时,我会启动一个等待结果的等待线程,然后更新结果标签。
当计算正在进行时,我将按钮更改为取消(Abbrechen)按钮。但我无法取消等待的线程
知道如何取消Thread t1?
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace Einsendeaufgabe_GPI13_4
{
public partial class Form1 : Form
{
int eingabe;
long[] arrFibo;
bool calculationComplete = false;
bool _shouldStop = false;
public Form1()
{
InitializeComponent();
this.backgroundWorker1.RunWorkerAsync(); // Start BackGroundworker
}
// Start Button
private void buttonStartStop_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy || calculationComplete)
{
try
{
eingabe = int.Parse(textBoxEingabe.Text);
buttonStartStop.Text = "Abbrechen";
buttonStartStop.Refresh();
labelErgebnis.Text = "";
buttonStartStop.Click -= buttonStartStop_Click;
buttonStartStop.Click += buttonStartStop_Click2;
if (arrFibo[eingabe] == 0)
{
labelErgebnis.Text = "Calculating...";
labelErgebnis.Refresh();
Thread t1 = new Thread(waitingMethod); // new thread, so if result is not calculated yet, teh waiting will be done in different thread
t1.Start();
}
else
{
labelErgebnis.Text = arrFibo[eingabe].ToString();
buttonStartStop.Text = "Berechnen";
labelErgebnis.Refresh();
buttonStartStop.Click -= buttonStartStop_Click2;
buttonStartStop.Click += buttonStartStop_Click;
}
}
catch (FormatException)
{
MessageBox.Show("Ungültige Eingabe. Nur Zahlen eingeben", "Eingabefehler");
}
}
}
//change event back to Click and cancel thread
private void buttonStartStop_Click2(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
buttonStartStop.Text = "Berechnen";
labelErgebnis.Text = "";
buttonStartStop.Click -= buttonStartStop_Click2;
buttonStartStop.Click += buttonStartStop_Click;
_shouldStop = true;
}
}
//waiting mehtod, when waiting for input is calculated
public void waitingMethod()
{
while (arrFibo[eingabe] == 0)
{
Thread.Sleep(500);
Console.WriteLine("Treadsleeping " + arrFibo[eingabe]);
}
labelErgebnis.Invoke(new Action(() => labelErgebnis.Text = arrFibo[eingabe].ToString()));
labelErgebnis.Invoke(new Action(() => buttonStartStop.Text = "Berechnen"));
labelErgebnis.Invoke(new Action(() => labelErgebnis.Refresh()));
buttonStartStop.Click -= buttonStartStop_Click2;
buttonStartStop.Click += buttonStartStop_Click;
}
// Fibonacci mehtod
public long calcFibo(BackgroundWorker bw, int n)
{
while (!bw.CancellationPending)
{
if (n == 0)
{
return 0;
}
else if (n == 1)
{
return 1;
}
else
{
long a = (calcFibo(bw, (n - 1)) + calcFibo(bw, (n - 2)));
arrFibo[n] = a;
}
break;
}
return arrFibo[n];
}
// Backgroundworker started at programstart
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
arrFibo = new long[92];
arrFibo[0] = 0;
arrFibo[1] = 1;
calcFibo(bw, 91);
if (bw.CancellationPending)
{
e.Cancel = true;
}
}
// When Backgroundworker Thread is finished
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
Console.WriteLine("Cancelled");
}
else
{
calculationComplete = true;
}
}
}
}
答案 0 :(得分:0)
看起来,你更适合与背景工作者一起工作。你可以在这里使用另一个后台工作者而不是一个线程。
所以,而不是创建线程:
Thread t1 = new Thread(waitingMethod);
您可以创建后台工作程序并在此处启动它:
waitingWorker.RunWorkerAsync();
然后您可以处理工作人员的事件并使用其CancellationPending
标志来取消线程:
private void waitingWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (arrFibo[eingabe] == 0 && !waitingWorker.CancellationPending)
{
Thread.Sleep(500);
Console.WriteLine("Treadsleeping " + arrFibo[eingabe]);
}
}
private void waitingWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
labelErgebnis.Invoke(new Action(() => labelErgebnis.Text = arrFibo[eingabe].ToString()));
...
}
如果您仍想使用某个帖子,那么您需要自己实施取消标记。您可以应用之前问题中的一个解决方案:How to Cancel a Thread?
至于现在,_shouldStop
从未在您的代码中使用过。您可以将其用作取消标记。使用@Fredrik Mörk's answer
bool _shouldStop = false;
private static object _shouldStopLock = new object();
//in buttonStartStop_Click2
lock (_shouldStopLock)
{
_shouldStop = false;
}
//in waiting method
bool localShouldStop = false;
while (arrFibo[eingabe] == 0 && !localShouldStop)
{
Thread.Sleep(500);
Console.WriteLine("Treadsleeping " + arrFibo[eingabe]);
lock (_shouldStopLock)
{
localShouldStop = _shouldStop;
}
}