I'm trying to improve some code and want a more generic implementation of creating timers that run async. In the situation below MethodA is working as expected and writes to console every 4 seconds. I'd expect MethodB to work too, but somehow it only executes one time.
public async Task InitTimers()
{
MethodA(TimeSpan.FromSeconds(4));
MethodB(TimeSpan.FromSeconds(4), ExecTimer());
}
private async Task MethodA(TimeSpan refreshTime)
{
var aTimer = new Timer();
aTimer.Elapsed += (s, e) => ExecTimer().ConfigureAwait(false);
aTimer.Interval = refreshTime.TotalMilliseconds;
aTimer.Enabled = true;
// Immediately trigger first time
ExecTimer().ConfigureAwait(false);
}
private async Task MethodB(TimeSpan refreshTime, Task task)
{
var aTimer = new Timer();
aTimer.Elapsed += (s, e) => task.ConfigureAwait(false);
aTimer.Interval = refreshTime.TotalMilliseconds;
aTimer.Enabled = true;
// Immediately trigger first time
task.ConfigureAwait(false);
}
private async Task ExecTimer()
{
Console.WriteLine("Hello World!");
}
Any idea what causes MethodB to only run once?
Your Timers are getting disposed when they fall out of scope once the methods MethodA/MethodB complete. You'd need to create them outside the Tasks or otherwise keep the Task running and the Timer in scope
Related
I am using System.Timers.Timer to execute an action every 10 secs. This action can also be called by other methods if some special condition arises or through UI. If the action is not called from the timer, I just reset the timer.
The code I am using...
timer = new Timer();
timer.Elapsed += (sender, args) => ExecuteAction();
timer.Interval = 10000;
timer.Enabled = true;
public void ExecuteActionAndResetTimer()
{
ExecuteAction();
timer.Stop();
timer.Start();
}
private void ExecuteAction()
{
// do the work...
}
The expected result, if 'X' is action called from timer (i.e. ExecuteAction), 'X' is action called from outside timer (i.e. ExecuteActionAndResetTimer) and 'o' is a second:
XooooXoXoXooooXoXooooX
This is working fine. I just want to know that can we do this using reactive extensions?
Thanks.
Yes, this is quite easily done with Rx.
Here's how:
var subject = new Subject<char>();
var query =
subject
.StartWith('X')
.Select(c =>
Observable
.Interval(TimeSpan.FromSeconds(10.0))
.Select(n => 'X')
.StartWith(c))
.Switch();
query.Subscribe(x => Console.Write(x));
Thread.Sleep(5000);
subject.OnNext('Q');
Thread.Sleep(15000);
subject.OnNext('W');
That produces the sequence XQXWXXXX with the final Xs going ad-infinitum.
I have a System.Timers.Timer instance created in the main thread. Now I call timer.Stop() to try to terminate that time and want to wait until the timer is really terminated. How could I do that?
Is there any similar method like System.Threading.Thread.Join()?
Here are some codes
//the main thread:
var aTimer = New Timer();
aTimer.Elapsed += SomeTimerTask;
aTimer.AutoReset = True;
aTimer.Start();
//some other logic...
//stop that timer:
aTimer.Stop();
//now I need to wait until that timer is really stopped,
//but I cannot touch the method SomeTimerTask().
//so I need something like System.Threading.Thread.Join()...
You could make use of a ResetEvents which are wait handles which can block a thread until you set the state to signaled:
class TimerAndWait
{
private ManualResetEvent resetEvent = new ManualResetEvent(false);
public void DoWork()
{
var aTimer = new System.Timers.Timer(5000);
aTimer.Elapsed += SomeTimerTask;
aTimer.Elapsed += ATimer_Elapsed;
aTimer.AutoReset = true;
aTimer.Start();
// Do something else
resetEvent.WaitOne(); // This blocks the thread until resetEvent is set
resetEvent.Close();
aTimer.Stop();
}
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
resetEvent.Set();
}
}
If you want a async/task-based solution you have to use the ThreadPool.RegisterWaitForSingleObject method
The Timer does not fire up the Elapsed when you call stop as you can read in the docs of the Stop()-Method:
Stops raising the Elapsed event by setting Enabled to false.
The Elapsed-Event is only triggered when the Timers Enabled-Property is set to true and the given Interval (which you have to set) is elapsed (this can happen multiple times).
So if you stop your Timer before the Interval is elapsed, you might have to trigger your code in some other way.
Now this one is driving me crazy. Using .NET Fx 4.0, I have the following delay mechanism:
private static Task Delay(double milliseconds)
{
var tcs = new TaskCompletionSource<bool>();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += (obj, args) => { tcs.TrySetResult(true); };
timer.Interval = milliseconds;
timer.AutoReset = false;
timer.Start();
return tcs.Task;
}
I call it in the following code:
// delay the execution of SendKey to let the dialog show up
var sendKeyTask = Delay(500).ContinueWith((_) =>
{
// this gets executed when the dialog is visible
SendKeys.Send(filePath);
}, TaskScheduler.FromCurrentSynchronizationContext());
MyButton.InvokeMember("click");
sendKeyTask.Wait(3000); //will time out after 3 seconds.
....
The problem is that SendKeys.Send(filePath); line is never executed. What am I missing?
What #PatrykĆwiek said.
Remove the Wait(3000), and if you want something to happen after sendKeyTask is completed - do it in a continuation (or do it in the sendKeyTask, as it is running on the current thread.. whatever is more appropriate).
I am looking for an alternative to calling Thread.Sleep which does not block the thread but instead returns the thread back into the thread pool. Does such a thing exist?
Use Task.Delay
await Task.Delay(delay);
If the thread is returning to the pool, then it isn't going to do any more work in the method in question. Make the next bit of the method a separate method, and create a Timer that calls it.
You can use also a Timer for example:
using System.Timers;
private void Main()
{
Timer t = new Timer();
t.Interval = 5000; // 5 seconds
t.AutoReset = false;
t.Elapsed += new SleepDone(TimerElapsed);
t.Start();
}
private void SleepDone(object sender, ElapsedEventArgs e)
{
Console.WriteLine("HERE WHAT COME AFTER SLEEP");
}
I am trying to delay my method by using a timer:
private System.Timers.Timer _delayTimer;
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
//_delayTimer.Enabled = true;
_delayTimer.Elapsed += _delayTimer_Elapsed;
_delayTimer.Start();
someMethod();
}
}
private void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// delay for 5 seconds
}
When i am get into delay() method i want to start the timer, than i want the 5 seconds delay and only after that i want to execute someMethod() and currently this not happen, after execute delay() the someMethod() executed without 5 seconds delay
Your current code sets up the timer and then immediately executes someMethod. Instead of this, you need to put the actual method call inside your Elapsed handler:
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
//_delayTimer.Enabled = true;
_delayTimer.Elapsed += _delayTimer_Elapsed;
_delayTimer.Start();
}
}
private void _delayTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
someMethod();
}
And if there's nothing else you intend to do you can simply write this inline:
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
_delayTimer.Elapsed += (o, e) => someMethod();
_delayTimer.Start();
If you're in .Net4.5(or using BCL.Async pack) you can use Task.Delay
private async void delay()
{
await Task.Delay(5000);
someMethod();
}
If you're under .Net4.5
Try the below code. I'll suggest you to use System.Threading.Timer
var timer = new System.Threading.Timer(x => someMethod(), null, 5000, System.Threading.Timeout.Infinite);\
Don't forget when you use Threading.Timer someMethod will be invoked in ThreadPool thread, If you're accessing UI you need to marshal the call to UI thread.
If you want the current thread to pause for five seconds, then call Thread.Sleep. For example:
Thread.Sleep(TimeSpan.FromSeconds(5));
DoSomething();
Use a timer if you want something to happen five seconds from now, while you're doing something else. When the timer elapses, the action will be executed on a thread pool thread.
Also, if you only want the timer to execute one time (rather than once every five seconds), be sure to set AutoReset to false.
You need to call someMethod in the timer's Elapsed handler:
private void delay()
{
_delayTimer = new System.Timers.Timer();
_delayTimer.Interval = 5000;
_delayTimer.AutoReset = false; //so that it only calls the method once
_delayTimer.Elapsed += (s,args) => someMethod();
_delayTimer.Start();
}
You could also use Task.Delay instead:
private void delay()
{
Task.Delay(5000)
.ContinueWith(t => someMethod());
}
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(5000);
/*
* Here Yopur code to do some method :D
* */
});