简体   繁体   English

如何在C#上的控制台应用程序中停止使用键盘输入的运行方法?

[英]How to stop a running method with keyboard input in a Console Application on C#?

In short, I'm utilizing C# to scientific computation and I've written a method that has a while loop that may run to a user-specified quantity of steps... Actually, this method may take too long to execute (like more than 5 hours). 简而言之,我正在利用C#进行科学计算,并且我编写了一个方法,该方法具有可以运行到用户指定数量的步骤的while循环......实际上,这种方法可能需要很长时间才能执行(如更多超过5小时)。 When it takes this long, I may want to stop the method pressing Esc key, for example. 如果需要这么长时间,我可能想要按Esc键停止方法,例如。

As I read something about breaking while , it is as simple as a Boolean flag or something like this. 当我读到关于破坏的东西while ,它就像Boolean标志或类似的东西一样简单。 So I thought in something like this: 所以我想到这样的事情:

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
}

Well, this is what I wondered until now... So please, could you give useful ideas to this extent? 嗯,这就是我想到的...直到现在......所以,请你能给出有用的想法吗? How can I wait for a user input (I thought about Events , but I'm not sure how to implement it here and I think that it will make the code even slower, if I have to listen to a key at every while step the code goes into... 我怎么能等待用户输入(我想到了Events ,但我不知道如何在这里实现它,我认为它会使代码更慢,如果我必须在每一步都要听一个键代码进入......

Well, any ideas or comments? 那么,有什么想法或意见吗?


Update : I think I should have had described better the problem. 更新 :我想我本来应该更好地描述这个问题。 All the solutions you gave me may solve this problem I proposed, but I think I was not completely reliable to my real problem. 你给我的所有解决方案都可以解决我提出的这个问题,但我认为我对我真正的问题并不完全可靠。 I don't know if I should ask another question or keep with this one... 我不知道是否应该问另一个问题或者继续这个问题......

You could run this method from a separate thread and set a stop variable when a key is pressed: 您可以从单独的线程运行此方法,并在按下键时设置停止变量:

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

and when a key is pressed, update stopProcessing accordingly: 当按下某个键时,相应地更新stopProcessing:

Console.ReadKey();
lock(myLock)
{
    stopProcessing = true;
}

If you're just wanting to stop the application, Ctrl-C from the command line will do it. 如果您只是想停止应用程序,命令行中的Ctrl-C将执行此操作。 If you really need to intercept input during a long running process, you might want to spawn a worker thread to do the long running process and then just use the main thread to interact with the console (ie Console.ReadLine()). 如果您确实需要在长时间运行的过程中拦截输入,您可能希望生成一个工作线程来执行长时间运行的进程,然后只使用主线程与控制台进行交互(即Console.ReadLine())。

Console.Key上的池可以及时进行,并相应地采取行动。

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");

    }
}

} }

You will need to do this using threading. 您需要使用线程来完成此操作。 When you start the task, spawn a new thread and execute the task on that thread. 当您启动任务时,生成一个新线程并在该线程上执行该任务。 Then in your Program.cs, wait for user input. 然后在Program.cs中,等待用户输入。 If the user enters something meaningful - in your case, the Esc key - alert the background thread of the action. 如果用户输入了有意义的内容 - 在您的情况下, Esc键 - 提醒操作的后台线程。 The simplest way to do this is by setting a static variable. 最简单的方法是设置静态变量。 The background thread will be checking this static variable and when it has been changed, the background thread will clean itself up and abort. 后台线程将检查此静态变量,当它被更改时,后台线程将自行清理并中止。

See the MSDN article on Threading . 请参阅有关线程MSDN文章

A code sample will be a little more in depth, but it would look something like this: 代码示例将更深入一些,但它看起来像这样:

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() { }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM