问题
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). When it takes this long, I may want to stop the method pressing Esc key, for example.
As I read something about breaking while
, it is as simple as a Boolean
flag or something like this. 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...
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...
回答1:
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:
Console.ReadKey();
lock(myLock)
{
stopProcessing = true;
}
回答2:
If you're just wanting to stop the application, Ctrl-C from the command line will do it. 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 (i.e. Console.ReadLine()).
回答3:
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. If the user enters something meaningful - in your case, the Esc
key - alert the background thread of the action. 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.
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() { }
}
回答4:
pool on Console.KeyAvailable in timely manner and take the action accordingly.
回答5:
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");
}
}
}
来源:https://stackoverflow.com/questions/5068309/how-to-stop-a-running-method-with-keyboard-input-in-a-console-application-on-c