currently I'm using a timer to poll every x seconds. I've seen that I could also use asyncronous tasks to execute a function after x seconds.
So I've created an example for reproduction. This is how I would use a polling timer
class UseTimer
{
public UseTimer()
{
Console.WriteLine("Foo");
Timer myTimer = new Timer(2000);
myTimer.Elapsed += (object sender, ElapsedEventArgs e) =>
{
Console.WriteLine("Bar");
myTimer.Enabled = false;
};
myTimer.Enabled = true;
Console.ReadLine();
}
}
The code first logs Foo, then waits 2 seconds for the first timer tick and then logs Bar. I tried to reproduce it by using async/await
class UseAsync
{
public UseAsync()
{
Console.WriteLine("Foo");
Do().Wait();
Console.ReadLine();
}
private async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
The behaviour seems to be the same when I test it with this code
class Program
{
static void Main(string[] args)
{
// UseAsync a = new UseAsync();
UseTimer t = new UseTimer();
}
}
I would like to know if I could or even should switch to async because it's easier to maintain and takes out complexity but remains the same way under the hood.
"Every x seconds" is different from "after x seconds".
If you need to run something (repeatedly) every x seconds, use a Timer.
If you need to run something (only once) after x seconds, use Task.Delay.
As noted in the comments, Task.Delay uses a System.Threading.Timer anyway, it's just easier to use for a single wait, and keeps your code clean.
Also, it's not wise to use asynchronous methods in a class constructor. Class constructors cannot be async, and thus you end up blocking the thread (as you did when using Wait()), or "fire and forget". If you need to do anything asynchronous while creating a new object, you can use a "factory method": a static method that creates the object for you. Then you make the constructor private to force everyone to use the factory method:
class UseAsync
{
private UseAsync() {}
public static async Task<UseAsync> CreateUseAsync()
{
var myC = new UseAsync();
await myC.Do();
return myC;
}
private async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
Then you can create an instance like this:
var a = await UseAsync.CreateUseAsync();
I've done this when I need to retrieve data from somewhere before an object is actually useful.
The console.readline should be outside useAsync method, if not the task Do will not be executed
class Program
{
static void Main(string[] args)
{
UseAsync.UseAsyn();
Console.ReadLine();
}
}
static class UseAsync
{
public static async Task UseAsyn()
{
Console.WriteLine("Foo");
await Do();
}
private static async Task Do()
{
await Task.Delay(2000);
Console.WriteLine("Bar");
}
}
Related
I have a WPF app running on .net 6 and an external device connected to it.
Initializing the device sometimes fails and I don't want to hold the UI thread trying to initialize it.
I want to run the following method (_device.Init()) in an async fashion and when it returns true, run Start() method.
edit: run it until it returns true from the _device.Init() method, not true for finishing the task
Is there a built-in functionality to do it with tasks? or any other "best practice" way?
Thank you :)
SomeDevice _device = new();
public async void Init()
{
// some other code
while (Task.Run(() => _device.Init()).Result == false)
{
}
Start();
}
public void Start()
{
// some other code
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
_device.Start();
}));
}
Instead of getting the Result of the Task (which may block the UI thread) you should await the Task:
public async void Init()
{
// some other code
while (!await Task.Run(() => _device.Init()))
{
}
Start();
}
The method should also be awaitable and be awaited when called, e.g. in an async Loaded event handler:
public async Task Init()
{
// some other code
while (!await Task.Run(() => _device.Init()))
{
}
Start();
}
...
await Init();
public async void Init()
{
var task = _device.Init();
//do work here
await task;
Start();
}
Should do the trick, it'll do the work and then wait for the task to complete before going to Start();
If you want to simply wait for init to finish and then run start it's even simpler with
await _device.Init().ContinueWith((x) => { Start();})
I would like to know if there 'right' method to loop one task forever?
What I've tried:
private static void A()
{
Task.Run(B);
}
private static async Task B()
{
while (true)
{
Task Delay = Task.Delay(10000);
await C();
await Delay;
}
}
private static async Task C()
{
// some async code that will work every 10s
}
It is working, but I want to understand is there any better options to do the same.
Thanks in advance.
I'm making a TCP server. I'm using async/await to handle the multi-threading. The methods I am using for listening to incoming clients and there subsequent messages look a bit like this:
private static async Task Listener()
{
while (Online)
{
TcpClient socket = await tcpListener.AcceptTcpClientAsync();
OnReceivedTcpClient(socket);
}
}
As you can tell, this method isn't expected to return anytime soon. The question I have is regarding how I should call this listener method. Currently the way I'm doing it is this:
(Console App)
In Program.cs within Main, I call Server.Start()
static void Main(string[] args)
{
Console.Title = "Server (Prototype)";
Server.Start(100, 26950);
ConsoleKeyInfo input;
do
{
input = Console.ReadKey();
// check input and do stuff
}
}
while (input.Key != ConsoleKey.C);
}
Server.Start initilises some values and then calls an event which in turn calls the listener
private static event EventHandler<EventArgs> StartEvent;
private static void OnStartEvent() => StartEvent?.Invoke(null, new EventArgs());
public static void Start(int maxClients, int port)
{
Stop();
Console.WriteLine("Starting server...");
Init(maxClients, port);
OnStartEvent();
}
private async void ServerOnStartEvent(object sender, EventArgs e)
{
Online = true;
Console.WriteLine($"Server started on port {Port}");
await Listener();
}
If I had called await Listener(); inside of Server.Start then that method would need the async keyword, and it would have to either return void (Which I know is not an ideal design) or return a Task which then means I would have to call _ = Server.Start() inside program.cs (Which also is not great design).
So my question is, is my solution a good way of awaiting an async Task method and are there better ways to go about it?
The way I usually deal with this is to also add a Stop-method. So Start launches the task and saves it in a field. the stop method requests the task to stop (by whatever means), and returns the task that was stored.
So the caller can await the result from the stop method, and once the task completes, the caller can be sure any resources are cleaned up etc.
A variant would be to let the Start method return something like a IAsyncDisposable, that could allow the using-statement to automatically stop and wait for cleanup when going out of scope.
Example:
public class MyClass
volatile bool stopRequested; // or use CancellationTokenSource
Task task;
public void Start() => task = Task.Run(DoWork); // Should probably make this "longRunning"
public void DoWork(){
while(!stopRequested){
// Do something that take a limited amount of time.
}
// Do cleanup
}
public Task Stop(){
stopRequested = true;
return task;
}
There's plenty of examples of people saying to use a Timer instead of Thread.Sleep(...) in an Azure Worker Role. No probs with that.
What I'm struggling to understand is how to code this.
Currently, I have the following (pseduo code)
_timer.Elapsed += (sender, args) => DoWork();
public override void Run()
{
while(true)
{
DoWork();
}
}
public void DoWork()
{
try
{
_timer.Stop();
// Now - do stuff ....
}
catch(....) { ... }
_timer.Start()
}
And what happens, is that the code enters the DoWork() method once and DoesStuff(tm).. fine .. starts the timer (say .. with a 30 second interval) and then exits that method.
Then, it returns back to the main Run() method .. which is in that loop. So it immediately comes back around and enters the DoWork() method again .. instead of waiting for the timer to fire it off.
So I'm not sure how to replace any Thread.Sleep(...) with Timers.
Any clues?
Clarification
I do not want to exit the Run() method :) I'm very happy to keep looping forever. What I'm stuck with, is replacing the standard Thread.Sleep(...) call (which blocks the thread) and replace that with a Timer, which most people suggest.
Update
Please do not link or suggest that I should use cancelSource.Token.WaitHandle.WaitOne(); as a solution. That is not what I'm trying to achieve here. Please note the post title!
I figure that if you want to solve this situation the way you outline here you will need a WaitHandle AND a Timer.
The short answer is here below. The long answer became a blog post: HowTo wait in a WorkerRole using Timer and EventWaitHandle over Thread.Sleep
I used an EventWaitHandle along with the Timer and came up with this solution:
public class WorkerRole : RoleEntryPoint
{
Waiter waiter;
public override bool OnStart()
{
waiter = new Waiter(WorkerConfiguration.WaitInterval);
return base.OnStart();
}
public override void Run()
{
while (true)
{
DoWork();
waiter.Wait();
}
}
public void DoWork()
{
// [...]
}
}
And here is the waiter class:
public class Waiter
{
private readonly Timer timer;
private readonly EventWaitHandle waitHandle;
public Waiter(TimeSpan? interval = null)
{
waitHandle = new AutoResetEvent(false);
timer = new Timer();
timer.Elapsed += (sender, args) => waitHandle.Set();
SetInterval(interval);
}
public TimeSpan Interval
{
set { timer.Interval = value.TotalMilliseconds; }
}
public void Wait(TimeSpan? newInterval = null)
{
SetInterval(newInterval);
timer.Start();
waitHandle.WaitOne();
timer.Close();
waitHandle.Reset();
}
private void SetInterval(TimeSpan? newInterval)
{
if (newInterval.HasValue)
{
Interval = newInterval.Value;
}
}
}
I'm having a small background thread which runs for the applications lifetime - however when the application is shutdown, the thread should exit gracefully.
The problem is that the thread runs some code at an interval of 15 minutes - which means it sleeps ALOT.
Now in order to get it out of sleep, I toss an interrupt at it - my question is however, if there's a better approach to this, since interrupts generate ThreadInterruptedException.
Here's the gist of my code (somewhat pseudo):
public class BackgroundUpdater : IDisposable
{
private Thread myThread;
private const int intervalTime = 900000; // 15 minutes
public void Dispose()
{
myThread.Interrupt();
}
public void Start()
{
myThread = new Thread(ThreadedWork);
myThread.IsBackground = true; // To ensure against app waiting for thread to exit
myThread.Priority = ThreadPriority.BelowNormal;
myThread.Start();
}
private void ThreadedWork()
{
try
{
while (true)
{
Thread.Sleep(900000); // 15 minutes
DoWork();
}
}
catch (ThreadInterruptedException)
{
}
}
}
There's absolutely a better way - either use Monitor.Wait/Pulse instead of Sleep/Interrupt, or use an Auto/ManualResetEvent. (You'd probably want a ManualResetEvent in this case.)
Personally I'm a Wait/Pulse fan, probably due to it being like Java's wait()/notify() mechanism. However, there are definitely times where reset events are more useful.
Your code would look something like this:
private readonly object padlock = new object();
private volatile bool stopping = false;
public void Stop() // Could make this Dispose if you want
{
stopping = true;
lock (padlock)
{
Monitor.Pulse(padlock);
}
}
private void ThreadedWork()
{
while (!stopping)
{
DoWork();
lock (padlock)
{
Monitor.Wait(padlock, TimeSpan.FromMinutes(15));
}
}
}
For more details, see my threading tutorial, in particular the pages on deadlocks, waiting and pulsing, the page on wait handles. Joe Albahari also has a tutorial which covers the same topics and compares them.
I haven't looked in detail yet, but I wouldn't be surprised if Parallel Extensions also had some functionality to make this easier.
You could use an Event to Check if the Process should end like this:
var eventX = new AutoResetEvent(false);
while (true)
{
if(eventX.WaitOne(900000, false))
{
break;
}
DoWork();
}
There is CancellationTokenSource class in .NET 4 and later which simplifies this task a bit.
private readonly CancellationTokenSource cancellationTokenSource =
new CancellationTokenSource();
private void Run()
{
while (!cancellationTokenSource.IsCancellationRequested)
{
DoWork();
cancellationTokenSource.Token.WaitHandle.WaitOne(
TimeSpan.FromMinutes(15));
}
}
public void Stop()
{
cancellationTokenSource.Cancel();
}
Don't forget that CancellationTokenSource is disposable, so make sure you dispose it properly.
One method might be to add a cancel event or delegate that the thread will subscribe to. When the cancel event is invoke, the thread can stop itself.
I absolutely like Jon Skeets answer. However, this might be a bit easier to understand and should also work:
public class BackgroundTask : IDisposable
{
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Stop()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
}
public void Dispose()
{
this.cancellationTokenSource.Dispose();
}
private void ThreadedWork(object state)
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
}
Or, including waiting for the background task to actually have stopped (in this case, Dispose must be invoked by other thread than the one the background thread is running on, and of course this is not perfect code, it requires the worker thread to actually have started):
using System;
using System.Threading;
public class BackgroundTask : IDisposable
{
private readonly ManualResetEventSlim threadedWorkEndSyncHandle;
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.threadedWorkEndSyncHandle = new ManualResetEventSlim();
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Dispose()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
this.threadedWorkEndSyncHandle.Wait();
this.cancellationTokenSource.Dispose();
this.threadedWorkEndSyncHandle.Dispose();
}
private void ThreadedWork(object state)
{
try
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
finally
{
this.threadedWorkEndSyncHandle.Set();
}
}
}
If you see any flaws and disadvantages over Jon Skeets solution i'd like to hear them as i always enjoy learning ;-)
I guess this is slower and uses more memory and should thus not be used in a large scale and short timeframe. Any other?