I have a kinda awkward problem, I'm working with C# and WPF in .NET 4.0 and what I need is a timer that will create only one thread but it will need to work in the background, so not in the main thread, the problem is using System.Windows.Forms.Timer or DispatchTimer will automatically force it to work on the main thread and be influenced by the UI, on the other side using System.Timers.Timer or System.Threading.Timer will create a new thread for every cycle that overpasses the time interval, this will happen since the code in the elapsed timer event is a bit big, although part of it is sent further to a background worker.
so I was thinking if it's possible to force, say the System.Timers.Timer, to work in the background and never spawn to more then one thread, also I am opened to other suggestions
Use System.Timers.Timer, which fires its elapsed event handler on a ThreadPool thread. As soon as you enter the event handler, stop the timer. At the end of your event handler, start the timer and it will start counting down from the beginning of its interval.
Here's a simple example with a 100ms timer that spends 2 seconds in it's elapsed event handler:
static void Main(string[] args)
{
System.Timers.Timer myTimer = new System.Timers.Timer(100);
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(myTimer_Elapsed);
myTimer.Start();
Console.ReadLine();
}
static void myTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
((System.Timers.Timer)sender).Stop();
Console.WriteLine(DateTime.Now.ToString("HH.mm.ss"));
System.Threading.Thread.Sleep(2000);
((System.Timers.Timer)sender).Start();
}
Just use a System.Threading.Timer with a period of 0 so that the callback runs only once. When everything is done, recharge the timer so it will fire again later. You'll have guaranteed only ever one thread running this way.
DispatcherTimer has a constructor overload that lets you do exactly what you want.
Use it in the context of your thread:
using System.Threading;
using WpfThreading = System.Windows.Threading;
...
Thread t = new Thread(() =>
{
var interval = TimeSpan.FromSeconds(3.0);
var priority = WpfThreading.DispatcherPriority.Background;
EventHandler callback = (a, e) => { };
var dispatcher = WpfThreading.Dispatcher.CurrentDispatcher; // dispatcher for this thread
WpfThreading.DispatcherTimer dt = new WpfThreading.DispatcherTimer(interval, priority, callback, dispatcher);
bool sameDispatchers = WpfThreading.Dispatcher.CurrentDispatcher == this.Dispatcher; // false
});
t.Start();
Related
I have a BackgroundWorker _worker
void _worker_DoWork(object sender, DoWorkEventArgs e)
{
_timer = new System.Timers.Timer();
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Interval = 5000;
_timer.Start();
}
When it gets to the line _timer.Start() it thinks it has finished so fires the RunWorkerCompleted event.
I don't want it to finish until the _timer.Interval time has been reached and the _timer Elapsed event has been trigger:
void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
for (int i = 1; i < 20; i++)
{
if (listBox1.InvokeRequired)
listBox1.Invoke((Action)(() => listBox1.Items.Add("Do Things Thread")));
else
listBox1.Items.Add("Do Things Completed");
_worker.ReportProgress((int)(((decimal)i / (decimal)20) * 100));
Thread.Sleep(1000);
}
_timer.Stop();
}
Because I need the BackgroundWorker to report back some progress.
How do I do this. I need it to run on a different thread.
So to round up the discussion and the solution.
System.Timers.Timer will automatically thread the timer event for you unless you supply a sync object, as discussed in MSDN:
If the SynchronizingObject property is null, the Elapsed event is
raised on a ThreadPool thread. If processing of the Elapsed event
lasts longer than Interval, the event might be raised again on another
ThreadPool thread. In this situation, the event handler should be
reentrant.
This means that the background worker becomes superfluos. You can simply have your timer event code run as is (as it uses invoke to interact with the UI anyhow).
It does mean that these events can run concurrently if they take a long time. However, you can of course stop and start the timer in the event callback.
Your _timer_Elapsed event is on a different thread. The instance of timer will expire as soon as the control flow passes through the _worker_DoWork function. The scope of your timer object variable is restricted to the function and hence it will not work this way.
I would suggest that you put put Thread.sleep(5000) in the timer _worker_dowork function itself. It will not affect your application as the thread will sleep and the gui will still be responsive.
I think, just by playing around with what I've done, is that I've invoked the progress bar, so I don't need the ReportProgress:
_worker.ReportProgress((int)(((decimal)i / (decimal)20) * 100));
Changed to :
if (progressBar1.InvokeRequired)
progressBar1.Invoke((Action)(() => progressBar1.Value = (int)(((decimal)i / (decimal)20) * 100)));
else
progressBar1.Value = (int)(((decimal)i / (decimal)20) * 100);
That means, I don't have to suspend the BackgroundWorker, and the timer was invoked on a different thread and will remain until disposed of????
I need a logic that would allow me to do something when a thread is running for more that X amount of seconds.
Like in this incredibly ugly example, here it will check every second and if the workerThread is running for 10 or more minutes it shows a message...
var timeWorking = TimeSpan.FromMinutes(0);
workerThread = new Thread(RunTask);
workerThread.Start(task);
while (workerThread.IsAlive)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
timeWorking = timeWorking.Add(TimeSpan.FromSeconds(1));
if (timeWorking.TotalMinutes < 10) continue;
timeWorking = TimeSpan.FromMinutes(0);
Console.Writeline("Here we go... the event")
}
Please help me to make it right...
What should I use Diagnostics.StopWatch, System.Timers.Timer or Threading.Timer ?
UPD: All the answers confused me even more...
The task is to check if workerThread is running for more than X amount of time, and if it is, call some method, reset the timer and check again if workerThread now is running for more than X amount of time since the last time we called the method... and so on and on...
UPD2: Basically I have a thread that does a processing based on information pulled from AmazonSQS queue. SQS Queue message has a visibility timeout. If the task will take longer than default visibility timeout - the message will be back to the queue before the task has finished. And then it will be picked up by another machine. To avoid that I need to extend visibility timeout of SQS message.
So I can do that by checking periodically if thread stil isALive then I can add couple of minutes to the message visibility timeout. After a minute and 50 seconds or so, I should check again and if thread still isALive then add couple more minutes and so on.
Since you know that the thread needs to do something after ten minutes, why not simply use an interval on the timer like this:
var interval = 1000 * 60 * 10; // ten minutes
var timer = new System.Timers.Timer(interval) { AutoReset = false };
timer.Elapsed += ((sender, eventArgs) =>
{
// Do your work here...
});
workerThread = new Thread(RunTask);
workerThread.Start(task);
timer.Start();
This way you are not checking each second and you will execute your code after a desired amount of time.
I think System.Timers.Timer is better suited based on what you've described. But, it depends. If you want to do something with the UI with the timer. Forms.Timer is better.
In either case, you could simply check if the thread is still alive when the timer Elapsed (or Ticked) and do something if it is.
e.g.
timeThreadStarted = DateTime.Now;
workerThread = new Thread(RunTask);
System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
workerThread.Start(task);
//...
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(workerThread != null && workerThread.IsAlive)
{
Console.WriteLine("thread has been running for {0}!", DateTime.Now - timeThreadStarted);
}
}
This checks the thread state after 1 second. If it is still Alive then it has been running for at least one second.
This has the benefit of not blocking any threads. If you have a UI and you want to do this, then you can't block the UI Thread (it will become unresponsive and provide a poor user experience).
You could also do Thread.Join with a TimeSpan like the example at http://msdn.microsoft.com/en-us/library/23f7b1ct.aspx so that you don't have to do a Thread.Sleep.
Note: either approach blocks calling thread until the time has elapsed. Not suitable for main/UI threads.
You can use a Timer that will raise an event once the elapsed time as triggered.
private static void Main(string[] args)
{
var thread = new Thread(
() =>
{
var timer = new System.Timers.Timer
{
Interval = 10000, //10s
AutoReset = false, //only raise the elapsed event once
};
timer.Elapsed += timer_Elapsed;
timer.Start();
while (true)
{
Console.WriteLine("Running...");
Thread.Sleep(1000); //Always put a thread to sleep when its blocking so it does not waste CPU cycles.
}
});
thread.Start();
}
private static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//thread is running for more that X (10s) amount of seconds
Console.WriteLine("Timer elapsed");
}
That is a simple example. In this example, the thread never exits. But you can add your own logic where necessary to get what you are trying to accomplish.
Short answer: Yes, use System.Timers.Timer
You can use the Task wait method, for example
var t = Task.Factory.StartNew(() => MyAction()); // MyAction is an action to be executed in parallel
bool check = t.Wait(10000); //wait for 10000 milliseconds
if (check)
{
// all ok
}
else
{
// over time
}
The Wait method blocks until the task ends or timeout happens. If you don't want to block your primary thread, you can run the example code using another task that works in parallel and checks the working task.
Working on a windows service, which has to process request in every predefined interval of time. Thread.Sleep does the work perfectly fine but problem with this is when service is invoked to be stopped, service freeze if thread is in sleep mode.
I have read about the alternative approach like Timer, but problem with that is after that defined interval new thread is getting started.
Is there a better way to achieve same result and not run in to issue.
What you're looking for is the ability to respond to the notification of two different events - (1) when the timer elapses and (2) when the service is stopped. #Anurag Ranhjan is on the right track with WaitHandle, but you have two events, not one. To properly handle this, do the following.
First, define the two events you care about using ManualResetEvent. You can use AutoResetEvent if you prefer; I just prefer resetting the events manually.
using System.Threading;
ManualResetEvent shutdownEvent = new ManualResetEvent();
ManualResetEvent elapsedEvent = new ManualResetEvent();
You need to trigger these events when they occur. For the shutdownEvent, it's easy. In the OnStop callback of your Windows service, just set the event.
protected override void OnStop
{
shutdownEvent.Set();
}
For the elapsedEvent, you could do this a couple different ways. You could create a background thread, i.e., the ThreadPool, that uses Thread.Sleep. When the thread wakes up, set the elapsedEvent and go back to sleep. Since it's a background thread, it won't hang your service when it shuts down. The alternative, as you've already suggested, is to use a timer. This is how I do it.
using System.Timers;
Timer timer = new Timer();
timer.Interval = 5000; // in milliseconds
timer.Elapsed += delegate { elapsedEvent.Set(); };
timer.AutoReset = false; // again, I prefer manual control
timer.Start();
Now that you've got events being set properly, put them in a WaitHandle array.
WaitHandle[] handles = new WaitHandle[]
{
shutdownEvent,
elapsedEvent
};
Instead of the WaitHandle.WaitOne method, use the WaitHandle.WaitAny method inside a while loop, like this.
while (!shutdownEvent.WaitOne())
{
switch (WaitHandle.WaitAny(handles))
{
case 0: // The shutdownEvent was triggered!
break;
case 1: // The elapsedEvent was triggered!
Process(); // do your processing here
elapsedEvent.Reset(); // reset the event manually
timer.Start(); // restart the timer manually
break;
default:
throw new Exception("unexpected switch case");
}
}
I've condensed this example from production code in my project. I know this mechanism works, but I may have missed something in the writeup. Let me know if you have any questions.
You can use WaitHandle.WaitOne instead. You can wait for closing event to trigger or timeout that you are specifying in predefined interval of time.
static AutoResetEvent seviceStopRequested = new AutoResetEvent(false);
....
((AutoResetEvent)stateInfo).WaitOne([timeout], false)
Then when Service stop is invoked, you can just trigger the event
seviceStopRequested .Set();
I usually use the following pattern:
public class MyJob
{
System.Threading.Timer _timer;
bool _isStopped;
public void MyJob()
{
_timer = new Timer(OnWork, null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(-1));
}
private void OnWork(object state)
{
//[.. do the actual work here ..]
if (!_isStopped)
_timer.Change(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(-1));
}
public void Stop()
{
_isStopped = true;
_timer.Change(TimeSpan.FromSeconds(-1), TimeSpan.FromSeconds(-1));
}
public void Start()
{
_isStopped = false;
_timer.Change(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(-1));
}
}
Key points:
Only using the initial interval gives you full control of when the timer is started again (i.e. the work time is not counted in the timer interval)
Changing the timer to -1 seconds pauses it until changed again
It should therefore work with all your requirements.
Use a Timer to add commands/tasks including the task for shutdown to a blocking queue. Make your service thread to wait for tasks on the blocking queue and execute them when available. The timer thread will keep adding the tasks to the queue periodically.
For what it is worth most of the blocking calls in the .NET BCL will respond to Thread.Interrupt. That is, they will not wait for the full amount of time specified when called and instead return immediately. However, I would avoid using this method and instead use a single ManualResetEvent to perform both the idle waiting and the shutdown signal. It would look like this.
public class MyServer : ServiceBase
{
private ManualResetEvent shutdown = new ManualResetEvent(false);
protected override void OnStart(string[] args)
{
new Thread(
() =>
{
while (!shutdown.WaitOne(YourInterval))
{
// Do work here.
}
}).Start();
}
protected override void OnStop()
{
shutdown.Set();
}
}
During debugging I can see that after Timer.Stop() or Timer.Enabled = false commands are executed, Timer is still running (Timer.Enabled = true). How is that possible?
This is possible when you stop the timer on a worker thread. For example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
Timer timer1;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
timer1 = new Timer();
timer1.Interval = 3000;
timer1.Start();
var t = new System.Threading.Thread(stopTimer);
t.Start();
}
private void stopTimer() {
timer1.Enabled = false;
System.Diagnostics.Debug.WriteLine(timer1.Enabled.ToString());
}
}
Output:
True
The timer must be stopped by the UI thread, the class takes care of it automatically. Quite similar to Control.BeginInvoke(). There's an explicit race, the Tick event handler can run after you stopped it. This can also happen on the UI thread if the very first timer you create is created on a worker thread. A splash screen for example. That's not healthy, you ought to fix that.
Calling Start after you have disabled a Timer by calling Stop will cause the Timer to restart the interrupted interval. If your Timer is set for a 5000-millisecond interval, and you call Stop at around 3000 milliseconds, calling Start will cause the Timer to wait 5000 milliseconds before raising the Tick event.
bear also in mind
Calling Stop on any Timer within a Windows Forms application can cause messages from other Timer components in the application to be processed immediately, because all Timer components operate on the main application thread. If you have two Timer components, one set to 700 milliseconds and one set to 500 milliseconds, and you call Stop on the first Timer, your application may receive an event callback for the second component first. If this proves problematic, consider using the Timer class in the System.Threading namespace instead.
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.stop.aspx
public void EnableTimer(bool state)
{
if (this.InvokeRequired) {
this.Invoke(new Action<bool>(EnableTimer), state);
} else {
this.Timer1.Enabled = state;
}
}
Try this code...
Got a quick question on creating a C# thread.
It needs to run every 10 minutes
The worker will do work then go into sleep for another 10 minutes
It can also be triggered to run immediately by calling Trigger()
It can be stopped by calling Stop()
I've created one with ManualResetEvent, which is set when Stop() is called. This works well but do I need to create another ManualResetEvent or wait handle in order to be able to trigger the worker immediately?
If by Stop you mean Stop waiting and don't run again then I think a Threading.Timer will be a good (lean) choice.
You can activate a timer with a DoWork() method and a 10 minutes interval. It will use the ThreadPool which seems the best choice here. Trigger() can queue DoWork directly on the Pool and Stop() can deactivate the Timer. DoWork() shouldn't use Sleep() and be suitable for the ThreadPool.
Using a timer here makes sense. Here's a quick code-snippet which I haven't tested.
private System.Timers.Timer _timer = null;
public void Constructor()
{
_timer = new System.Timers.Timer(600000);
_timer.Elapsed += new ElapsedEventHandler(t_Elapsed);
}
public void ForceDoWork()
{
//unsubscribe to timer event, so work dowsnt get fired twice
_timer.Elapsed -= new ElapsedEventHandler(t_Elapsed);
StartWorking();
_timer.Elapsed += new ElapsedEventHandler(t_Elapsed);
}
public void StartWorking()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkToBeDone));
}
private void WorkToBeDone(object state)
{
//work here
}
public void t_Elapsed(object sender, ElapsedEventArgs e)
{
StartWorking();
}
Yes, you'll need another wait handle to force thread to execute. You'll basically have to WaitOne for this handle for 10 minutes, thus either elapsing a timeout or continuing whenever the wait handle becomes signalled.
Don't forget to switch that handle to a non-signalled state, though.