Как отменить поток, ожидающий фонового работника? - PullRequest
0 голосов
/ 13 мая 2018

Я пишу программу на C #, используя WinForms в Visual Studio 2017.
Задача состоит в том, чтобы числа Фибоначчи начинали вычисляться при запуске программы (при загрузке формы)

КогдаЯ ввожу число через текстовое поле, которое уже рассчитано и записано в массив.отображается число.
Когда я ввожу число, которое еще не рассчитано, я запускаю поток ожидания, ожидающий результата, а затем обновляю метку результата.
Когда вычисления продолжаются, я изменяюкнопку отменить (Abbrechen) кнопку.Но я не могу отменить ожидающую ветку.
Есть идеи, как я могу отменить тему 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;
            }
        }


    }
}

1 Ответ

0 голосов
/ 14 мая 2018

Использование другого фонового рабочего

Кажется, вам удобнее работать с фоновым работником. Вы можете использовать другой фоновый рабочий вместо потока здесь.

Итак, вместо создания потоков:

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()));
    ...
}

Использование потока

Если вы все еще хотите использовать поток, вам нужно будет самостоятельно установить флаг отмены. Вы можете применить одно из решений из предыдущего вопроса: Как отменить тему?

На данный момент _shouldStop никогда не используется в вашем коде. Вы можете использовать его в качестве флага отмены. Используя код из @ ответа Фредрика Мёрка

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;
    }
}    
...