C# консоль Прервать несколько потоков - PullRequest
0 голосов
/ 04 мая 2020

Я работаю над консольной версией тестера ссылок. Я запускаю функцию в нескольких потоках, но не могу отменить их нажатием клавиши. Есть идеи, как мне это сделать?

try
{
    Thread[] tr = new Thread[Variables.Threads];
    int i = 0;
    while (i < Variables.Threads && Variables.running)
    {
        tr[i] = new Thread(new ThreadStart(Program.Runner));
        i++;
    }
    //Start each thread  
    foreach (Thread x in tr)
    {
        x.Start();
    }
    //Console.ReadKey();  

    Task.Factory.StartNew(() =>
    {
        while (Colorful.Console.ReadKey().Key != ConsoleKey.Escape);
        Variables.running = false;
        foreach (Thread x in tr)
        {
            x.Abort();
        }
        Program.Menu();
    });

}
catch (Exception)
{
}

РЕДАКТИРОВАТЬ: Когда мои потоки близки к концу, все мое приложение не перемещается после

1 Ответ

0 голосов
/ 04 мая 2020

Консоль не является хорошей средой для начала изучения многозадачности, а тем более - многопоточности. Мой совет для изучения многозадачности - и особенно многопоточности - это BackgroundWorker в приложении WindowsForms. Очередь событий делает главное поддержание вашего приложения без блокировки ввода-вывода. И хотя BackgroundWorker ужасно устарел и должен быть удален из производственного кода, это довольно хорошие учебные круги.

Также ваш текущий код проглатывает исключения, , включая фатальные . Это основной грех обработки исключений . Не делайте этого.

В конце дня вы можете выполнять только проверку отмены и отчеты о ходе выполнения между отдельными строками кода. В этом примере BGW у меня было преимущество в том, что я все равно должен был написать все циклы - так что в картах была глубокая проверка отмены и отчеты о ходе выполнения. Но если вы используете «чей-то другой код», высоки шансы, что вам придется ждать возврата одного вызова функции, прежде чем вы сможете сообщить и проверить.

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion

Однако в вашем случае Multi threading кажется несерьезным. Multi Tasking без потоков, вероятно, будет лучше. Потоки помогают, только если у вас есть задача CPU . А «проверка ссылок» звучит как Сетевая задача . У потоков есть некоторые дополнительные головные боли, которых вам лучше избегать.

...