How to use console command to quit infinite loop in C# - c#

So I have an infinite loop that runs some code and I want it to run forever until a user types an exit command. However the problem I am having is when the code reaches the ReadLine command, it stays there until it receives a valid input from the console. How can I code it so it will move on to the rest of the code and only read from the console if there is a valid input
while(true)
{
uint quit = Uint32.Parse(Console.ReadLine());
if(quit == 1){
break;
}
else{
//some other code
}
}

You will need to use an Asynchronous library which monitors the console for keystrokes and will pipe out commands.
I would recommend becoming familiar with IAsyncEnumerable
The pattern usually is to implement some form of IAsyncEnumerable<YourApplicationEvent> service.
Whenever you need to pipe out to the console you can have the async service yield return a YourApplicationEvent, while also piping out a YourApplicationEvent whenever the user hits enter to send command.
I use a method like this usually for this type of task:
public async IAsyncEnumerable<string> ConsoleEvents([EnumeratorCancellation] CancellationToken token)
{
await using var reader = Console.OpenStandardInput();
var commandBuffer = new List<byte>();
while (!token.IsCancellationRequested)
{
var buffer = new byte[4096];
var readCount = await reader.ReadAsync(buffer, token);
var command = new string(Encoding.UTF8.GetChars(buffer, 0, readCount));
yield return command.TrimEnd();
}
}

You're going to want to look into asynchronous programming.
Essentially, you're going to want to create a Task that takes care of running your code in the background, and you can wait for some console input to cancel the task if needed.
Typically this is achieved by implementing a Cancellation Token, which you can update from your loop that is waiting for user input.
Here is an example app I just made that should show you how this is accomplished:
class Program
{
static void Main(string[] args)
{
// create our token source here
var cancellationTokenSource = new CancellationTokenSource();
// and get the actual cancellation token from the token source
var cancellationToken = cancellationTokenSource.Token;
// have the Task library run an async task for us, and pass in our cancellation Token
Task.Run(
async () => {
// while our task is not cancelled
while (!cancellationToken.IsCancellationRequested)
{
// perform our code
Console.WriteLine("Simulated background code.");
await Task.Delay(1000);
}
}, cancellationToken);
// say hi
Console.WriteLine("Hello World!");
// while we havent requested a cancellation we loop
while (!cancellationToken.IsCancellationRequested)
{
// wait on reading a line
var escape = Console.ReadLine();
// if that line is quit we cancel the token
if (escape == "quit")
cancellationTokenSource.Cancel();
}
Console.WriteLine("See you later.");
}
}
}

Related

GetContextAsync() with Cancellation Support

So I'm spinning up a HttpListener to wait for an OAuth2 response. In an ideal world, this is only going to be alive for a few seconds while the user logs in in the browser and we get posted the token.
I'd also like for this to have a CancellationToken so that the user can stop listening after a delay should they so wish.
My initial idea was to use something along the lines of:
_listener.Start();
Task<HttpListenerContext> t = _listener.GetContextAsync();
while (!cancelled.IsCancellationRequested)
{
if (t.IsCompleted)
{
break;
}
await Task.Run(() => Thread.Sleep(100));
}
HttpListenerContext ctx = t.Result;
//...
_listener.Stop();
But that doesn't sit right with me for so many reasons (weird async usage, polling, etc.).
So then I thought I might be able to use the synchronous version _listener.GetContext() in conjunction with Task.Run(func<T>, CancellationToken):
_listener.Start()
HttpListenerContext ctx = await Task.Run(() => _listener.GetContext(), cancelled);
//...
_listener.Stop();
This is a little better, the code's at least tidier, although it seems hacky using a synchronous version of the method asynchronously with a Task...
However this doesn't behave how I'd expect (aborting the running task when the token is cancelled).
This strikes me as something that really ought to be fairly simple to do so I assume I'm missing something.
So my question is thus... How do I listen asynchronously with a HttpListener in a cancellable fashion?
Because the GetContextAsync method does not support cancellation, it basically means that it is unlikely you can cancel the actual IO operation, yet unlikely to cancel the Task returned by the method, until you Abort or Stop the HttpListener. So the main focus here is always a hack that returns the control flow to your code.
While both the answers from #guru-stron and #peter-csala should do the trick, I just wanted to share another way without having to use Task.WhenAny.
You could wrap the task with a TaskCompletionSource like this:
public static class TaskExtensions
{
public static Task<T> AsCancellable<T>(this Task<T> task, CancellationToken token)
{
if (!token.CanBeCanceled)
{
return task;
}
var tcs = new TaskCompletionSource<T>();
// This cancels the returned task:
// 1. If the token has been canceled, it cancels the TCS straightaway
// 2. Otherwise, it attempts to cancel the TCS whenever
// the token indicates cancelled
token.Register(() => tcs.TrySetCanceled(token),
useSynchronizationContext: false);
task.ContinueWith(t =>
{
// Complete the TCS per task status
// If the TCS has been cancelled, this continuation does nothing
if (task.IsCanceled)
{
tcs.TrySetCanceled();
}
else if (task.IsFaulted)
{
tcs.TrySetException(t.Exception);
}
else
{
tcs.TrySetResult(t.Result);
}
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
return tcs.Task;
}
}
And flow the control like this:
var cts = new CancellationTokenSource();
cts.CancelAfter(3000);
try
{
var context = await listener.GetContextAsync().AsCancellable(cts.Token);
}
catch (TaskCanceledException)
{
// ...
}
I would suggest creating cancelable infinite task (Task.Delay(Timeout.Infinite, token) for example) and use Task.WhenAny. Something like that:
var cts = new CancellationTokenSource(); // token source controled by consumer "outside"
var token = cts.Token;
var httpListener = new HttpListener();
httpListener.Start();
var t = httpListener.GetContextAsync();
// to cancel the infinite delay task if listener finishes first
var localCts = CancellationTokenSource.CreateLinkedTokenSource(token);
var completed = await Task.WhenAny(t, Task.Delay(Timeout.Infinite, localCts.Token));
if (completed == t) // check that completed task is one from listener
{
localCts.Cancel(); // cancel the infinite task
HttpListenerContext ctx = t.Result;
//...
}
httpListener.Stop();
Here is yet another solution:
var cancellationSignal = new TaskCompletionSource<object>();
var contextTask = _listener.GetContextAsync();
using (cancelled.Register(state => ((TaskCompletionSource<object>)state).TrySetResult(null), cancellationSignal))
{
if (contextTask != await Task.WhenAny(contextTask, cancellationSignal.Task).ConfigureAwait(false))
break; //task is cancelled
}
Because we can't await the CancellationToken that's why have to apply the following trick
The CancellationToken does expose a Register method, where we can define a callback which will be called whenever the cancellation occurs
Here we can provide a delegate which sets an awaitable to completed
So, we can await that task
In order to create a Task which is set to completed whenever the cancellation occurs I've used TaskCompletionSource. You could also use SemaphoreSlim or any other signalling object which has async wait, like AsyncManualResetEvent.
So, we pass the cancellationSignal to the Register as a state parameter
Inside the delegate we have to cast it back to TCS to be able to call the TrySetResult on it
Inside the using block we await a Task.WhenAny
It will return that Task which finishes first
If that Task is the cancellation then we can break / return / throw ...
If that Task is the contextTask then we can continue the normal flow

Serial port awaiter - cancel if device is not responding for 5 secs | when flag doesnt change

I'm trying to make a app that comunicates with a device through serial port.
I'm lacking the idea to "stop" the program when there is no response for some time.
I got the idea to make a flag that I'm setting to false while sending data, in my DataReceiveEvent I'm changing the flag to true. But at the same time I want a timer that if no response is registered will fire an event.
I thought of using async Tasks.
var delay = Task.Run(async () => { await Task.Delay(3000); return false;});
var flag = Task.Run(async () => { await isFlagChanged(); return isFlagChanged});
var result = await Task.WhenAny(delay, flag);
bool res = await result;
but I don't know how to determine if flag had changed. I don't even know if that's a good idea...
Any sugestions?
Have your Async Task reset a CancellationTokenSource timeout each time it receives information.
If it doesn't receive any data then the CancelationToken will fire and your Task can exit. Your function that will be reading the serial port, needs to be checking the CancellationToken.
eg:,
static async Task MyTaskAsync(CancellationTokenSource cts)
{
await Task.Yield();
CancellationToken ct = cts.Token;
var rnd = new Random();
while (true)
{
var next = rnd.Next(10);
Console.WriteLine(next);
if (next == 1)
{
await Task.Delay(500, ct); // Simulate receiving no data by waiting longer the timeout
ct.ThrowIfCancellationRequested();
}
else
{
await Task.Delay(100, ct); // Simulate receiving data by waiting less than the timeout
cts.CancelAfter(500);
}
ct.ThrowIfCancellationRequested();
}
}
static async Task Main(string[] args)
{
var cts = new CancellationTokenSource(500); // Auto cancel after 500ms
try
{
await MyTaskAsync(cts);
}
catch (OperationCanceledException)
{
Console.WriteLine("The task exited because the Cancellation timeout period expired.");
}
}

c# - Trying to Dispose task while it is executing code

While "worker" is executing piece of code, I'm closing the whole window and I want to dispose it on closing that window because it is finishing it's code otherwise.
Task worker = Task.Factory.StartNew(new Action(() =>
{
// some code here
}
Unfortunetly, when I call worker.Dispose() in Close() there is an Exception:
A task may only be disposed if it is in a completion state
(RanToCompletion, Faulted or Canceled)
Any suggestions how I can dispose it while it is working?
You need to write your code so that your task will accept a cancellation token. That's basically just a flag that can be checked by the code in your task, which if updated you would provide logic to handle, having your task's logic safely handle how to terminate its execution, rather than simply stopping at some unknown state. Running the below sample code in LinqPad should give you a reasonable example of what's going on:
void Main()
{
var form = new Form();
var label = new Label(){Text = string.Format("{0:HH:mm:ss}", DateTime.UtcNow), AutoSize = true};
form.Controls.Add(label);
var taskController = new CancellationTokenSource();
var token = taskController.Token;
var task = Task.Run(() =>
{
for (var i=0; i<100; i++)
{
var text = string.Format("{0:HH:mm:ss}", DateTime.UtcNow);
Console.WriteLine(text); //lets us see what the task does after the form's closed
label.Text = text;
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation Token Detected");
break;
}
Thread.Sleep(1000);
}
}, token);
form.FormClosed += new FormClosedEventHandler(
(object sender, FormClosedEventArgs e) =>
{taskController.Cancel();}
);
form.Show();
}
Key Points:
Create an instance of CancellationTokenSource. This is a simple object which will allow you to communicate when you wish to cancel to your task.
var taskController = new CancellationTokenSource();
Fetch the token from this source
var token = taskController.Token;
Run the task, passing a reference to the token
var task = Task.Run(() =>
{
//...
, token
}
Add logic within the task to check the status of this token at suitable points, & handle it appropriately.
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation Token Detected");
break;
}
Add logic to call the Cancel method when you wish to cancel the task. In the above code I've put this under the Form's FormClosed event handler's logic:
taskController.Cancel();
See https://binary-studio.com/2015/10/23/task-cancellation-in-c-and-things-you-should-know-about-it/ for a good write up / related ways to cancel a task.
Side Note
In the above example I was a bit lazy. Each iteration of the loop I check the cancellation token; but then (if not cancelled) wait 1 second before looping. Since the cancel logic only comes into play when the if statement is evaluated that means that we have to wait 1 second for the cancellation to take effect, which isn't great; if that delay was larger (e.g. 5 minutes), it could be really painful. One solution is outlined here: https://stackoverflow.com/a/17610886/361842
i.e. replace
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation Token Detected");
break;
}
Thread.Sleep(1000);
with
if (token.IsCancellationRequested)
{
Console.WriteLine("Cancellation Token Detected");
break;
}
token.WaitHandle.WaitOne(1000);
See https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle.waitone?view=netframework-4.7.2 for documentation on the WaitOne method.
Try using a cancellation token.
var cancellationTokenSource = new CancellationTokenSource();
var t = Task.Factory.StartNew(() =>
{
// Your code here
}, cancellationTokenSource.Token).ContinueWith(task =>
{
if (!task.IsCompleted || task.IsFaulted)
{
// log error
}
}, cancellationTokenSource.Token);
Keep the cancellationTokenSource handy and cancel it in your Close()

is it necessary to wait for termination of all the threads before request gets complete in MVC

I am working on a web api project in which user perform some action and all the related user get notification regarding the user activity. To notify every user i am starting a new thread which perform the desire action. is it necessary to wait for this thread to terminate before request gets complete and return result to user.
P.S. Execution time for thread may increase with no of user.
Please Suggest any alternate if possible
Program Logic(Presently i am using await function to wait for async function to execute)
public async Task<IHttpActionResult> doSomething(arguments)
{
.
.
.
.
<!-- Perform some operation which includes some database transcations--!>
if(operation succesed)
{
await Notification(userid);
}
return result;
}
static void Main(string[] args)
{
var userIds = new[] { 1, 2, 3, 4, 5};
Console.WriteLine("Updating db for users...");
// Start new thread for notficiation send-out
Task.Run(() =>
{
foreach (var i in userIds)
Console.WriteLine("Sending notification for #user " + i);
}).ContinueWith(t => Console.WriteLine("Notifcation all sent!"));
Console.WriteLine("Return the result before notification all sent out!");
}
If you remove await in front of Task.Run() (equivalent to Notifcation() which returns Task<> in your case) and run then it will create separate thread for notification send-out.
public async Task<IHttpActionResult> doSomething(arguments)
{
bool isInsertDone ,isUpdateDone = false;
//create thread list
var task = new List<Task>();
// parallel tasks to thread list and execute that tasks
task.Add(Task.Run(() =>
{`enter code here`
isInsertDone = insertData(arguments)
}));
task.Add(Task.Run(() =>
{
isUpdateDone updateData(arguments)
}));
// wait for execute all above tasks
Task.WaitAll(task.ToArray());
// return response by result of insert and update.
return Ok<bool>(isInsertDone && isUpdateDone);
}
If it is going to be a long running function and there is no direct impact on the current function then there is no need to wait. Fire and forget. You can safely remove the await.
public async Task<IHttpActionResult> doSomething(arguments) {
//... Perform some operation which includes some async database transactions
if(operation succesed) {
NotificationsAsync(userid); //Start notifications and continue
}
return result;
}
I would suggest using a messaging queue for jobs like that but that is a more advanced topic which is out of scope for this question.

C#: CancellationToken doesn't cancel blocking method

.NET 4.5.1: It appears, I can't cancel a blocking method running inside a task using the CancellationTokenSource built-in timeout.
class Program
{
static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
// MainAsync from http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app
static async Task MainAsync(string[] args, System.Threading.CancellationToken token)
{
Console.WriteLine("Starting MainAsync");
var cts = new System.Threading.CancellationTokenSource(3000);
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
var success = await task;
Console.WriteLine("Did the task complete succesfuly?", success);
}
}
The output from the above Short, Self Contained, Correct Example (I hope it's correct) is:
Starting MainAsync
Starting task...
Recieving...
Why does the task doesn't cancel, no exception is thrown?
As I state on my blog, "You keep using that CancellationToken there. I do not think it means what you think it means."
In particular, the CancellationToken passed to StartNew will only cancel the starting of the delegate. If you want the delegate itself to support cancellation, then the delegate itself will have to observe the CancellationToken.
I am not sure but I guess you are confusing "requesting a cancellation" with "terminating or aborting a thread/task".
These are two completly different things. According to the description about the Canellation in Managerd Threads the provided functionality enables you to send something like a signal, indicating, that the operation in progress shall be stopped.
How and if you react on that signal is - as a programmer - up to you.
In your example you've started a new task
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
which does not handle the cancellation nor is it suitable to do so.
Canellation would be used e.g. if you want to break out of a loop with many iterations - therefore you would check in each iteration whether the CancellationToken.IsCancellationRequested has been set to true or not.
If so, you can react accordingly.
What you want is to abort the thread that's behind the current task which is in my opinion only possible by creating a new instance of the Thread class for yourself and handle the abort accordingly.

Categories

Resources