Consider the following:
//base stuff
private readonly ConcurrentQueue<message> queue = new ConcurrentQueue<message>();
private readonly MyCacheData _cache = new MyCacheData ();
//setuo
timer = new Timer { Interval = 60_000, AutoReset = true };
timer.Elapsed += OnTimedEvent;
httpClient.Timeout = new TimeSpan(0, 0, 60); // 60 seconds too
//
// each 60 seconds
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (cache 30 minutes old)
{
//Fire and Forget GetWebDataAsync()
// and continue executing next stuff
// if I await it will wait 60 seconds worst case
// until going to the queue and by this time another
// timed even fires
}
// this always should execute each 60 seconds
if (queue isnt empty)
{
process queue
}
}
// heavy cache update each 10-30 minutes
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
}
finally
{
release Semaphore
}
}
}
Colored: https://ghostbin.com/paste/6edov
Because I cheat and use the cheap ConcurrentQueue solution I don't really care much about what happens during GetWebDataAsync(), I just want to fire it and do its job, while I instantly go to process queue because it always must be done each 60 seconds or timer resolution.
How do I correctly do that, avoid much overhead or unnecessary thread spawning?
EDIT: got an answer for my case elsewhere
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
async void DoGetWebData() => await GetWebDataAsync()
if (condition)
{
DoGetWebData(); // Fire&Forget and continue, exceptions handled inside
}
//no (a)waiting for the GetWebDataAsync(), we already here
if (queue isnt empty)
{
//process queue
}
}
private async Task GetWebDataAsync()
{
if (Semaphore.WaitAsync(1000))
{
try
{
//fetch WebData update cache
//populate Queue if needed
}
catch (Exception)
{
//log stuff
}
finally
{
///always release lock
}
}
}
Task.Run(...);
ThreadPool.QueueUserItem(...);
Anything wrong with these?...
How about something like that:
ManualResetEvent mre = new ManualResetEvent(false);
void Foo()
{
new Thread(() =>
{
while (mre.WaitOne())
{
/*process queue item*/
if (/*queue is empty*/)
{
mre.Reset();
}
}
}) { IsBackground = true }.Start();
}
void AddItem()
{
/*queue add item*/
mre.Set();
}
Call an async method from another async method without await statement
Related
I'm currently trying to implement a real-time multithreading software in C#. I need 3 threads. Every thread execution has to be finished before a deadline (500µs / 100µs / 50µs). The threads must run parallel during the whole runtime (until the user shuts down the program).
Is there a mecanism that can guarantee that the thread execution will not pass the deadline?
Here is my code :
static void Main(string[] args)
{
Thread thread1 = new Thread(FirstThread);
Thread thread2 = new Thread(SecondThread);
Thread thread3 = new Thread(ThirdThread);
thread1.start();
thread2.start();
thread3.start();
}
static void FirstThread()
{
while(true)
{
SleepMicroSec(500);
}
}
static void SecondThread()
{
while(true)
{
SleepMicroSec(100);
}
}
static void ThirdThread()
{
while(true)
{
SleepMicroSec(50);
}
}
private static void SleepMicroSec(long microSec)
{
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)) < microSec)
{
}
}
I expect the scheduler to be able to perform the context switching if the Task deadline is reached.
Thanks in advance for your answers !
Here is a method that invokes repeatedly an action in a background thread, aborting and restarting the thread every time the deadline is passed. It also accepts a CancellationToken to allow for premature cancellation of the procedure (before the end of the program).
private static void RepeatInBackgroundThread(Action action, int timeout,
CancellationToken cancellationToken)
{
var timer = new System.Timers.Timer(timeout);
timer.AutoReset = false; // to raise the Elapsed event only once
var thread = new Thread(() =>
{
while (true)
{
if (cancellationToken.IsCancellationRequested) return;
timer.Start();
action();
timer.Stop();
}
});
timer.Elapsed += (sender, e) =>
{
thread.Abort();
thread.Join(); // Wait for the thread to die
if (cancellationToken.IsCancellationRequested) return;
RepeatInBackgroundThread(action, timeout, cancellationToken);
};
thread.IsBackground = true;
thread.Start();
}
Usage example:
var random = new ThreadLocal<Random>(() => new Random());
var cts = new CancellationTokenSource();
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 1000)), 500, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 200)), 100, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 100)), 50, cts.Token);
//cts.CancelAfter(10000);
It should be noted that aborting threads is not a good practice in general.
I have seen plenty of examples (here and elsewhere) of creating a non-reentrant timer by stopping the timer when the elapsed handler method is called and starting it again at the end of the elapsed handler method. This seems to be the recommended approach. The problem with this approach is that you will have a gap in time while the Elapsed Handler Method is running. You could end up with timing that is off by quite a lot within a short period of time.
So I was thinking about a better approach and I can up with the idea to use a bool to determine the state of the Timer, and whether the Elapsed Handler is currently running or not, it is is running then the call to the Elapsed Handler is returned immediately and the rest is not executed.
Below is the basic Idea
volatile bool _IsProcessingElapsedMethod = false;
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
//** DO Something here
_IsProcessingElapsedMethod = false;
}
There has to be a reason I have never seen anyone do this. Am I missing some obvious Gotcha? It seems like a pretty easy solution.
Below is a compilable example.
using System;
using System.Threading.Tasks;
using System.Timers;
namespace QuestionNon_ReEntrantTimer
{
class Program
{
static private int Timer1_ElapsedCount = 1;
static void Main(string[] args)
{
NonReEntrantTimer timer1 = new NonReEntrantTimer(500);
timer1.Elapsed += Timer1_Elapsed;
timer1.Start();
Console.WriteLine("Press Any key to Exit");
Console.ReadKey();
}
private static void Timer1_Elapsed(object sender, ElapsedEventArgs e)
{
int delayTime;
if(Timer1_ElapsedCount < 10)
{
delayTime = 300 * Timer1_ElapsedCount++;
}
else
{
Timer1_ElapsedCount++;
delayTime = 400;
}
Console.WriteLine($"Timer1_Elapsed Call Count is {Timer1_ElapsedCount} Waiting for {delayTime} ms");
Task.Delay(delayTime).Wait();
}
}
public class NonReEntrantTimer : IDisposable
{
Timer _timer = new Timer();
public event ElapsedEventHandler Elapsed;
volatile bool _IsProcessingElapsedMethod = false;
public NonReEntrantTimer(double interval)
{
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
public void Close() => _timer.Close();
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
Elapsed?.Invoke(sender, e);
_IsProcessingElapsedMethod = false;
}
public void Dispose()
{
_timer.Dispose();
}
}
}
I would propose this simple async pattern. It executes the given Action every ts, but starts countdown to the next execution before starting the current iteration. If the execution takes more time than ts, the next iteration is postponed till after the previous one finishes.
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
var currentDelay = Task.Delay(ts, ct);
while (!ct.IsCancellationRequested)
{
await currentDelay; // waiting for the timeout
currentDelay = Task.Delay(ts, ct); // timeout finished, starting next wait
a(); // executing action in the meanwhile
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
You can stop the iterations by cancelling the token. You can offload the action execution to the thread pool by starting the operation with Task.Run.
Update: if you want the timer to try catching up after the slow action, you can do it with some minor changes:
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
for (var targetTime = DateTime.Now + ts; !ct.IsCancellationRequested; targetTime += ts)
{
var timeToWait = targetTime - DateTime.Now;
if (timeToWait > TimeSpan.Zero)
await Task.Delay(timeToWait, ct);
a();
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
btnLog.TouchUpInside += async (sender, e) =>
{
try
{
SomeAction();
}
catch (Exception exe)
{
Log(exe.message);
}
};
If we click btnLog 2,3 time SomeAction() is getting called 2,3 times,
I want to call it only once i mean the last call,
How to reset that event,
Thanks.
There are a few ways to achieve what you require, so I'll list a couple of them.
The first is to simply disable the button at the start of it's click event and then re-enable it after the 'work' you need to do has completed, this ensures that the 'work' only gets ran through once at a time.
This can be done like so:
btnLog.TouchUpInside += async (sender, e) =>
{
btnLog.isEnabled = false;
try
{
SomeAction();
}
catch (Exception exe)
{
Log(exe.message);
}
btnLog.isEnabled = true;
};
Or alternatively you can use an Interlocked.CompareExchange
private CancellationTokenSource cts = new CancellationTokenSource();
private CancellationToken token = new CancellationToken();
private int running;
btnLog.TouchUpInside += async (sender, e) =>
{
if (Interlocked.CompareExchange(ref running, 1, 0) == 0)
{
try
{
Task.Run(async () =>
{
if (!token.IsCancellationRequested)
{
await doWork();
running = 0;
return;
}
running = 0;
}, token);
}
catch (TaskCanceledException tcEx)
{
running = 0;
}
}
};
private Task doWork()
{
//Async method
}
The above only proceeds to run the Task, if the int 'running' equals zero, it also adopts a cancellation token, should you wish to cancel the doWork asynchronous method on a page change etc. We use this a fair amount to manage Tasks across our platforms.
You can unsubscribe that method by creating an EventHandler in order to use the method by its name:
EventHandler method = async (sender, e) =>
{
try
{
SomeAction();
btnLog.TouchUpInside -= method;
}
catch (Exception exe)
{
Log(exe.message);
}
};
btnLog.TouchUpInside += method;
I'm using a System.Timers.Timer in my application. Every second I run a function which does some job. The thing is, this function can block for some little time (it reads then processes a large file from disk). I want to start that function only if its previous "execution instance" has completed. I thought I could achieve this with a Mutex:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
That doesn't work, "foos" still appear every second. How can I achieve this?
EDIT: You're right, it makes no sense to start a new thread to handle this. I thought only System.Threading.Timer is launched in a separate thread.
I'm not sure why you are using a new thread to start the timer, since timers run on their own thread, but here's a method that works. Simply turn the timer off until you are done with the current interval.
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}
If you want to skip the tick if another is already working you can do this.
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}
Easiest way I know of to do this kind of thing:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
The handler still runs, but the very first thing it does is make sure that another handler isn't running, and if one is, it stops immediately.
For timers executing handlers more quickly (like 3-4 times a second), this has the possibility to race; two threads could proceed past the guard clause before one of them sets the bit. You can avoid this with a couple of lock statements, similar to a Mutex or Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
This will ensure that only one thread can ever be examining or modifying isRunning, and as isRunning is marked volatile, the CLR won't cache its value as part of each thread's state for performance; each thread has to look at exactly the same memory location to examine or change the value.
You can follow the following pattern to skip doing the indicated work if another invocation of this method is still running:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
The approach that you were using with a Mutex will result in addition ticks waiting for earlier ticks to finish, not skipping invocations when another is still running, which is what you said you wanted. (When dealing with timers like this its common to want to skip such ticks, not wait. If your tick handlers regularly take too long you end up with a giant queue of waiting handlers.)
I need a method to run accurately every 5 minutes. I can't use Timer because I noticed it will slowly become out of sync (i.e. it will eventually run at 00:01, 00:06, 00:11, 00:16, and so on).
Although it needs to be accurate, I don't need it to be too precise. Every 5 minutes +/- 1 second will be okay, just as long as after days of running, it will still tick accurately on the 5 minute marks.
What I have thought of so far is creating a Timer with an Interval of 1 second that constantly checks DateTime.Now to see if the next 5 minute mark is passed. I am wondering if there is a more elegant solution or something in the C# libraries that I have missed.
Edit: I have the following template now, which is working to my requirements.
public class ThreadTest
{
private Thread thread;
private long nextExecutionTime;
private long interval;
public void StartThread(long intervalInMillis)
{
interval = intervalInMillis * TimeSpan.TicksPerMillisecond;
nextExecutionTime = DateTime.Now.Ticks;
thread = new Thread(Run);
thread.Start();
}
private void Run()
{
while (true)
{
if (DateTime.Now.Ticks >= nextExecutionTime)
{
nextExecutionTime += interval;
// do stuff
}
}
}
}
if you are not happy with Timer?
then you can try to make your thread sleep for 5 mintues, instead of using Timer
have a look this, hope it helps
using System;
using System.Threading;
public class Worker
{
// This method will be called when the thread is started.
public void DoWork()
{
while (!_shouldStop)
{
Task.Factory.Start(() =>
{
// do you task async
})
Thread.Sleep(300000);
}
}
public void DoWork2()
{
var watch = new Stopwatch();
while (!_shouldStop)
{
watch.Start();
Task.Factory.Start(() =>
{
// do you task async
})
while(watch.Elapsed.ElapsedMilliseconds < 300000);
watch.Stop();
watch.Reset();
}
}
public void RequestStop()
{
_shouldStop = true;
}
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
// Loop until worker thread activates.
while (!workerThread.IsAlive);
while (true)
{
//do something to make it break
}
// Request that the worker thread stop itself:
workerObject.RequestStop();
workerThread.Join();
}
}
or you can try this: