I want to create a program that makes keyboard event for every 10 seconds.
but once my code starts to perform,
it can't stop until it's finished.
Is there any way to stop to close the program??
Can I make it detect my keyboard action by two seconds, like detect hitting ESC to stop the program?
My code is at below.
private void StartAction()
{
int minutes = 2;
Process pr = Process.Start("notepad.exe");
for (int a = 0; a < minutes; a++)
{
for (int b = 0; b < 6; b++)
{
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
Thread.Sleep(2000);
SendKeys.Send("KeyBoard Action");
}
}
}
Sometimes its easier to just use a timer.
using System.Threading;
...
private static Timer _myTimer;
private static volatile bool _isCancled;
private static void Main(string[] args)
{
_myTimer = new Timer(Callback, null, 2000, 2000);
Console.ReadLine();
}
private static void Callback(object state)
{
if (_isCancled)
{
_myTimer.Change(0, 0);
return;
}
try
{
//SendKeys.Send("KeyBoard Action");
Console.WriteLine("blah");
}
catch (Exception ex)
{
//Handle Exception
}
}
or another way
Task.Run(async () =>
{
while (!_isCancled)
{
await Task.Delay(2000);
//SendKeys.Send("KeyBoard Action");
Console.WriteLine("blah");
}
});
Just for completeness, the optimal way to cancel a task is using a Cancellation Token. You can read more about them here
CancellationToken Structure
Propagates notification that operations should be canceled.
Add a condition inside the for loop, so that it will exit when requested.
if (condition)
{
break;
}
Edit: Because of the Thread.Sleep everywhere, the program won't actually be able to have a conditional change, example, if you're condition was when the user pressed f1, the condition would never become true because the Thread.Sleep would block the thread, therefore the users input would never be recognized. Try not to use so many Thread.Sleep, if any at all. If it is absolutely necessary, I advise you to use an async method, or use Timers.
Related
I have a code. The goal of this is to cancel a task with a CancellationToken, I know that it possible to do with return; in loop, but I want to do it with CancellationToken. I tried to do it, but it does not work and I have no idea why.
The task
break a task loop on dropNumber
static CancellationTokenSource cancellationTokenSource = null;
static async Task Main(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
try
{
Task.Run(() => CountLoopAsync(cancellationTokenSource.Token, 4),cancellationTokenSource.Token);
}
catch(OperationCanceledException ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.White;
Console.WriteLine("Task is cancelled!");
Console.ResetColor();
}
finally
{
cancellationTokenSource.Dispose();
}
}
private static void CountLoopAsync(CancellationToken token, int dropNumber)
{
for(int i = 0; i < 10; i++)
{
Console.WriteLine(i);
if (dropNumber == i)
{
cancellationTokenSource.Cancel();
}
}
}
}
Your Task.Run it's done with await so you don't go to Cancel sentence until the task has finished. Use Task.Run without await to allow continue running and execute the Cancel
UPDATE
I think that your example if not so good because you are trying to execute all code in a sequencial way when the use of task is usually to run code in background, in an asynchronous form. Also, I think that stop with a predefined value is a non sense: in that case, change the final step in your "for" instead of the use of a token.
You don't Cancel in the task code. If you know in that code when to cancel, you simply return. The purpose of the token is allow to cancel externally to task code. And doing that, you can't control when the task finish because it depends of something external. Maybe, for example, when an user click "Cancel" button.
Usually, your counter code try to calculate all. But, been a long time operation, you give to the user the oportunity to cancel in any moment.
Encapsulate your code in a class:
public class YourClass : IDisposable
{
private CancellationTokenSource _cancellationTokenSource = null;
private Task _task = null;
public void Wait(int milliSeconds)
{
this._task.Wait(milliSeconds, this._cancellationTokenSource.Token);
}
public void Dispose()
{
this._cancellationTokenSource?.Dispose();
this._task?.Dispose();
}
public async Task RunLongOperationInBackground()
{
this._cancellationTokenSource = new CancellationTokenSource();
this._task = Task.Run(
() => CountLoopAsync(this._cancellationTokenSource.Token),
this._cancellationTokenSource.Token);
await this._task;
}
public void Abort()
{
// Cancel the operation
this._cancellationTokenSource?.Cancel();
}
private static void CountLoopAsync(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
// Uncomment to simulate task takes some time to finish
//Thread.Sleep(3000);
// You don't know when the action will be cancelled. If you know that, you don't
// need the cancellation: you can do the for until your well known end
if (token.IsCancellationRequested)
{
break;
}
}
}
}
This class allow you run an operation (RunLongOperationInBackground) and also cancel in any moment (Abort). So, you run your task and, in any moment, you can cancel the task. If you look the CountLoopAsync code, it tries to execute all but, it checks sometimes (in each iteration in this case) the token, and if someone has request to cancel, you exit the for. But you can do whatever you want. For example, you may run always up to next hundred so, even if token has been cancelled, you may continue up to next hundred. Or if the cancellation has been requested near to the end of the operation, you may decide continue. The token only tell you that outside wants terminate.
Create a Form (instead a console) with 2 buttons, for a more realistic example:
public partial class Form1 : Form
{
private readonly YourClass _yourClass;
public Form1()
{
this.InitializeComponent();
this._yourClass = new YourClass();
}
private async void OnStartButtonClick(object sender, EventArgs e)
{
await this._yourClass.RunLongOperationInBackground();
}
private void OnCancelButtonClick(object sender, EventArgs e)
{
this._yourClass.Abort();
}
private void OnForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (this._yourClass != null)
{
// Wait, for example 30 seconds before end the appication
this._yourClass.Wait(30000);
this._yourClass.Dispose();
}
}
}
You create your class in the constructor. The Start button run your long time operation (you may want use a Delay in each for iteration to be able to cancel before terminate). In any time you can click de Abort button to cancel the operation. And in that moment, in your "for" the token tell you that has been cancelled and you exit the for.
I think that the problem is here:
cancellationTokenSource.Dispose();
It seems that the cancellationTokenSource is disposed prematurely. You are not supposed to dispose it before all associated work has completed. In your case you must probably wait for the completion of the Task.Run before calling Dispose.
Task.Run(() => CountLoopAsync(cancellationTokenSource.Token, 4),
cancellationTokenSource.Token).Wait();
I am learning about tasks and async/await in c#. So please consider the stupidity of my question.
There is an event DummyEvent in a class. An event handler DummyEventHandler is subscribed to this event and it handles a large amount of CPU bound task, which is actually not needed to be used so frequently.
For that reason, if DummyEvent is fired continuously, I want DummyEventHandler to respond either at a reduced frequency, or respond at the end of that continuity.
So, my idea is to extract the large task into a separate Task and made it to delay 500 millisecond before it proceeds. After the delay ends, it will check whether the same Task has been scheduled again (continuous event fire) or not and avoid the large calculation if true.
Here is my naive implementation of that idea:
int ReducedCall = 0;
int TotalCallActual = 0;
protected void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
LargeCPUBoundTask(); // there is a green underline here, but I think it's ok, or.. is it?
}
async Task LargeCPUBoundTask()
{
ReducedCall = TotalCallActual;
await Task.Delay(500);
// if this task is called again in this time, TotalCallActual will increase
if (ReducedCall == TotalCallActual)
{
// do all the large tasks
……
ReducedCall = 0;
TotalCallActual = 0;
}
}
But the problem is, I am not getting what I want. The line Task.Delay(500) doesn't actually await , or, if it does wait, there is something wrong because I experience staggering .
Any better idea, or any improvement / correction?
Ask for any additional information.
Thanks
You can leverage Reactive Extensions to do this:
void Main()
{
var generator = new EventGenerator();
var observable = Observable.FromEventPattern<EventHandler<bool>, bool>(
h => generator.MyEvent += h,
h => generator.MyEvent -= h);
observable
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(s =>
{
Console.WriteLine("doing something");
});
// simulate rapid firing event
for(int i = 0; i <= 100; i++)
generator.RaiseEvent();
// when no longer interested, dispose the subscription
subscription.Dispose();
}
public class EventGenerator
{
public event EventHandler<bool> MyEvent;
public void RaiseEvent()
{
if (MyEvent != null)
{
MyEvent(this, false);
}
}
}
The Throttle operator as coded above will allow a value (event) getting true every second.
So in the above code example the text doing something will only be printed once (after a second) even while the event is fired many times.
Edit
By the way, the reason for the green line is that your Task is not awaited. To fix it alter the code to:
protected async void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
await LargeCPUBoundTask(); // there is no more green underline here
}
Unfortunately this will still not solve your issue as an event cannot be awaited so if the event is raised again while LargeCPUBoundTask is still running another call to LargeCPUBoundTask will be made so the work is overlapping if you get what I mean. In other words, that is why your code does not work.
I would use the timer event handler instead of your DummyEventHandler
Just adjust the frequency in milisencond of the timer and that will be it. You can create a timer via code without adding it to a form as a control. I think it is in the common controls lib.
Hope this helps. Good luck.
I spent some more time thinking about this problem and the assumption I made with my first solution was that the event is continuously firing, when it could just be firing part of the time for a while and then stop in the real problem.
In cases like this, the CPU bound task would only occur on the first event firing and then if the events finish firing before that CPU bound task completes, the remaining events would not get handled. But you wouldn't want to handle all of them, just the "last" one (not necessarily the actual last one, just one more to take care of the "cleanup").
So I've updated my answer to include the use case where there are frequent yet intermittent (i.e. burst of events then quiet) the correct thing would occur and a final run of the CPU bound task would happen (but still no more than 1 CPU bound task running at a time).
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Sender s = new Sender();
using (Listener l = new Listener(s))
{
s.BeginDemonstration();
}
}
}
class Sender
{
const int ATTEMPTED_CALLS = 1000000;
internal EventHandler frequencyReducedHandler;
internal int actualCalls = 0;
internal int ignoredCalls = 0;
Task[] tasks = new Task[ATTEMPTED_CALLS];
internal void BeginDemonstration()
{
int attemptedCalls;
for (attemptedCalls = 0; attemptedCalls < ATTEMPTED_CALLS; attemptedCalls++)
{
tasks[attemptedCalls] = Task.Run(() => frequencyReducedHandler.Invoke(this, EventArgs.Empty));
//frequencyReducedHandler?.BeginInvoke(this, EventArgs.Empty, null, null);
}
if (tasks[0] != null)
{
Task.WaitAll(tasks, Timeout.Infinite);
}
Console.WriteLine($"Attempted: {attemptedCalls}\tActual: {actualCalls}\tIgnored: {ignoredCalls}");
Console.ReadKey();
}
}
class Listener : IDisposable
{
enum State
{
Waiting,
Running,
Queued
}
private readonly AutoResetEvent m_SingleEntry = new AutoResetEvent(true);
private readonly Sender m_Sender;
private int m_CurrentState = (int)State.Waiting;
internal Listener(Sender sender)
{
m_Sender = sender;
m_Sender.frequencyReducedHandler += Handler;
}
private async void Handler(object sender, EventArgs args)
{
int state = Interlocked.Increment(ref m_CurrentState);
try
{
if (state <= (int)State.Queued) // Previous state was WAITING or RUNNING
{
// Ensure only one run at a time
m_SingleEntry.WaitOne();
try
{
// Only one thread at a time here so
// no need for Interlocked.Increment
m_Sender.actualCalls++;
// Execute CPU intensive task
await Task.Delay(500);
}
finally
{
// Allow a waiting thread to proceed
m_SingleEntry.Set();
}
}
else
{
Interlocked.Increment(ref m_Sender.ignoredCalls);
}
}
finally
{
Interlocked.Decrement(ref m_CurrentState);
}
}
public void Dispose()
{
m_SingleEntry?.Dispose();
}
}
I'm in the process of writing a simple "Score Attack" Poker game. A player assembles poker hands which are worth points as a timer ticks down. My problem is a game over scenario.
My game logic runs in a single thread since the game itself is so simple. I need to know how to terminate that thread as it is, with the player no longer able to make input. I've read on the MSDN that the safe way to do this is to use a loop to cause the thread's method to return and end the thread. The problem I run into is that my game requires user input, and the user input would cause the loop to not be checked at the moment the timer ticks to zero.
The code so far uses the Thread.Abort(), and it works, but from my searching on this site that is universally regarded as a bad idea. Is there any way I could set a condition that would terminate the thread safely regardless of methods within said thread needing input? (Console.ReadLine())
Code for the game loop and timer callback that aborts the thread:
private void GameLoop()
{
double stash = 0;
while (true)
{
player.SwapCards(gameDeck);
Table.WriteInfo("Stash This Hand? y/n");
if (Console.ReadLine().Equals("y"))
{
countdown += (int)ScoreHand(player.Hand);
stash += ScoreHand(player.Hand);
BankHand();
}
}
}
private void TimeDrop(object state)
{
countdown--;
Debug.WriteLine(countdown);
if (countdown == 0)
{
GameThread.Abort();
GameOverThread.Start();
Timer.Dispose();
}
}
As it sits the loop simply runs until the thread is aborted.
Edit:
Upon request, the code the starts the threads:
public Game()
{
gameDeck = new Deck();
InitPlayer();
DealHand();
countdown = 60;
GameThread = new Thread(GameLoop);
GameOverThread = new Thread(GameOver);
Timer = new Timer(new TimerCallback(TimeDrop), null, 0, 1000);
Timer.Change(0, 1000); //Ensures timer won't be garbage collected
GameThread.Start();
}
This sort of thing can be implemented easier and cleaner using async/await rather than threads.
First we need to wrap the blocking console input method with one that is cancellable (and async). The method polls the console using KeyAvailable and asynchronously delaying while checking the CancellationToken.
public static async Task<ConsoleKeyInfo> ReadKeyAsync(CancellationToken cancellationToken)
{
while (!Console.KeyAvailable)
{
await Task.Delay(100, cancellationToken);
}
return Console.ReadKey();
}
Now we can start this async method and pass a cancellation token from a CancellationTokenSource that will automatically cancel after a specific amount of time (10 seconds as an example).
public static async Task Main(string[] args)
{
Console.WriteLine("You have 10 seconds to press the Y key...");
var cts = new CancellationTokenSource(10_000);
try
{
while (true)
{
var key = await ReadKeyAsync(cts.Token);
if (key.Key == ConsoleKey.Y)
{
Console.WriteLine("Good job!");
break;
}
else
{
Console.WriteLine("Wrong Key");
}
}
}
catch (OperationCanceledException)
{
Console.Write("Time up!");
}
}
I wish my method to wait about 500 ms and then check if some flag has changed. How to complete this without blocking the rest of my application?
You can use await Task.Delay(500); without blocking the thread like Sleep does, and with a lot less code than a Timer.
Thread.Sleep(500) will force the current thread to wait 500ms. It works, but it's not what you want if your entire application is running on one thread.
In that case, you'll want to use a Timer, like so:
using System.Timers;
void Main()
{
Timer t = new Timer();
t.Interval = 500; // In milliseconds
t.AutoReset = false; // Stops it from repeating
t.Elapsed += new ElapsedEventHandler(TimerElapsed);
t.Start();
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hello, world!");
}
You can set AutoReset to true (or not set it at all) if you want the timer to repeat itself.
I don't really understand the question.
If you want to block before checking, use Thread.Sleep(500);
If you want to check asynchronously every x seconds, you can use a Timer to execute a handler every x milliseconds.
This will not block your current thread.
It the method in question is executing on a different thread than the rest of your application, then do the following:
Thread.Sleep(500);
System.Threading.Thread.Sleep(500);
Update
This won't block the rest of your application, just the thread that is running your method.
Using a timer should do the trick
if you need to use a thread then here is an example
void Main()
{
System.Threading.Thread check= new System.Threading.Thread(CheckMethod);
check.Start();
}
private void CheckMethod()
{
//Code
Thread.Sleep(500);
}
Asynchron Task:
var task = new Task (() => function_test()); task.Start();
public void function_test() { `Wait for 5000 miliseconds` Task.Delay(5000);` }
I've recently been struggling with the same issue where I needed an action to be run on schedule without blocking the UI.
Here's my solution:
private void Button_Click(object sender, RoutedEventArgs e)
{
RunOnSchedule(interval, cancellationToken);
}
private void RunOnSchedule(int interval, CancellationToken cancellationToken)
{
// Start the task you want to run on schedule
TaskToRunOnSchedule(args);
Task.Run(async () =>
{
// This loop checks if the task was requested to be cancelled every 1000 ms
for (int x = 0; x < interval; x+=1000)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
await Task.Delay(1000);
}
}).GetAwaiter().OnCompleted(() =>
{
// Once the task for delaying is completed, check once more if cancellation is requested, as you will reach this point regardless of if it was cancelled or not.
if (!cancellationToken.IsCancellationRequested)
{
// Run this method again
RunOnSchedule(interval, cancellationToken);
}
});
}
In a WinForms application, when I want to wait on the main thread without blocking the app, I usually use
private void Wait (double milliseconds)
{
DateTime next = System.DateTime.Now.AddMilliseconds(milliseconds);
while (next > System.DateTime.Now)
Application.DoEvents();
}
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...
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;
}
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()).
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() { }
}
pool on Console.KeyAvailable in timely manner and take the action accordingly.
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");
}
}
}