Как остановить запущенный метод с помощью ввода с клавиатуры в консольном приложении на C #? - PullRequest
5 голосов
/ 21 февраля 2011

Короче говоря, я использую C # для научных вычислений и написал метод с циклом while, который может выполняться с указанным пользователем количеством шагов ... На самом деле этот метод может занять слишком много времени для выполнения.(вроде больше 5 часов).Когда это занимает много времени, я могу остановить метод, например, нажав клавишу Esc .

Когда я читаю что-то о взломе while, это так же просто, как Boolean флаг или что-то вроде этого.Поэтому я подумал примерно так:

public Double? Run(int n)
{
    int i = 0;
    while ((i < n) && (/* inputkey != ConsoleKey.Escape */))
    {
        // here goes the heavy computation thing
        // and I need to read some "inputkey" as well to break this loop
        i++;
    }
    // I'm not worried about the return statement, as it is easy to do...
    // returns null if the user skipped the method by pressing Escape
    // returns null if the method didn't converged
    // returns the double value that the method calculated otherwise
}

Ну, это то, о чем я думал до сих пор ... Так что, пожалуйста, не могли бы вы дать полезные идеи на этот счет?Как я могу ждать ввода пользователя (я думал о Events, но я не уверен, как реализовать это здесь, и я думаю, что это сделает код еще медленнее, если мне придется слушать клавишу каждый разшаг, в который входит код ...

Ну, есть идеи или комментарии?


Обновление : я думаю, что я должен был лучше описать проблему. ВсеРешения, которые вы дали мне, могут решить эту проблему, которую я предложил, но я думаю, что я не был полностью уверен в своей реальной проблеме. Я не знаю, должен ли я задать другой вопрос или оставить этот вопрос ...

Ответы [ 5 ]

6 голосов
/ 21 февраля 2011

Вы можете запустить этот метод из отдельного потока и установить переменную остановки при нажатии клавиши:

object myLock = new object();
bool stopProcessing = false;

public Double? Run(int n)
{
    int i = 0;
    while (i < n)
    {
        lock(myLock)
        {
            if(stopProcessing)
                break;
        }
        // here goes the heavy computation thing
        // and I need to read some "inputkey" as well to break this loop
        i++;
    }
}

, а когда клавиша нажата, обновить stopProcessing соответственно:

Console.ReadKey();
lock(myLock)
{
    stopProcessing = true;
}
5 голосов
/ 21 февраля 2011

Если вы просто хотите остановить приложение, Ctrl-C из командной строки сделает это. Если вам действительно нужно перехватывать ввод во время длительного процесса, вы можете создать рабочий поток для выполнения длительного процесса, а затем просто использовать основной поток для взаимодействия с консолью (т. Е. Console.ReadLine ()).

2 голосов
/ 21 февраля 2011
using System;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
    class Program
    {
        static bool _cancelled = false;
        static void Main( string[] args )
        {
            var computationTask = Task.Factory.StartNew(PerformIncredibleComputation);
            var acceptCancelKey = Task.Factory.StartNew(AcceptCancel);


        while (!acceptCancelKey.IsCompleted && ! computationTask.IsCompleted)
        {

            computationTask.Wait (100);        
        }

        if( acceptCancelKey.IsCompleted && !computationTask.IsCompleted )
        {
            computationTask.Wait (new System.Threading.CancellationToken ());
        }
        else if(!acceptCancelKey.IsCompleted)
        {
            acceptCancelKey.Wait(new System.Threading.CancellationToken());
        }


    }


    private static void PerformIncredibleComputation()
    {
        Console.WriteLine("Performing computation.");
        int ticks = Environment.TickCount;
        int diff = Environment.TickCount - ticks;
        while (!_cancelled && diff < 10000)
        {
           //computing  
        }
        Console.WriteLine("Computation finished");
    }

    private static void AcceptCancel()
    {

        var key = Console.ReadKey(true);
        Console.WriteLine("Press Esc to cancel");
        while(key.Key != ConsoleKey.Escape)
        {
            key = Console.ReadKey(true);
        }
        _cancelled = true;
        Console.Write("Computation was cancelled");

    }
}

}

2 голосов
/ 21 февраля 2011

пул на Console.KeyAvailable своевременно и принять соответствующие меры.

1 голос
/ 21 февраля 2011

Вам нужно будет сделать это с помощью потоков.Когда вы запускаете задачу, создайте новый поток и выполните задачу в этом потоке.Затем в вашем Program.cs, дождитесь ввода пользователя.Если пользователь вводит что-то значимое - в вашем случае, клавиша Esc - предупреждает фоновый поток действия.Самый простой способ сделать это - установить статическую переменную.Фоновый поток будет проверять эту статическую переменную, и когда она будет изменена, фоновый поток будет очищаться и прерываться.

См. Статью MSDN о потоке .

* 1007.* Пример кода будет немного глубже, но он будет выглядеть примерно так:
public class Program.cs
{
    public static myFlag = false;
    public void Main()
    {
        thread = new Thread(new ThreadStart(DoWork));
        thread.Start();
        Console.ReadLine();
        myFlag = true;
    }
    public static DoWork()
    {
        while(myFlag == false)
        {
            DoMoreWork();
        }
        CleanUp()
    }
    public static DoMoreWork() { }
    public static CleanUp() { }

}
...