What I want to do. I want to SomeMethod will be called periodically. Therefore, I want to timer will be started from backgroung thread after body of background thread method is passed. _timer.Start() was invoked, but TickHandler doesn't;
code:
using Timer = System.Windows.Forms.Timer;
class TestTimer
{
private Timer _timer;
private Thread _thread;
public TestTimer()
{
// create and initializing timer. but not started!
_timer = new Timer();
_timer.Tick += TickHandler;
_timer.Interval = 60000; // 1 minute
// create and start new thread
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void TickHandler(object sender, EventArgs e)
{
// stop timer
_timer.stop();
//some handling
// run background thread again
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void SomeMethod()
{
// some operations
// start timer!
TimerStart();
}
private void TimerStart()
{
_timer.Start();
}
}
By monkey method I found if add Delegate like this
internal delegate void TimerDelegate();
And replace string
TimerStart();
with
Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);
all works fine. Somebody can explain me what is the trick?
You've got things mixed up a bit.
If you want a timer that fires on a background thread, you don't have to create a thread to start it (it doesn't matter which thread calls the Start method). Just use System.Timers.Timer, and each Elapsed event will occur on a thread-pool thread.
If you want a timer that fires on the UI thread, since it looks like you're using WPF, you should use System.Windows.Threading.DispatcherTimer, and not the Windows Forms timer you've been using. You should create the timer (i.e. call new) on a particular UI thread, and every Tick event will occur on that thread. Again, it doesn't matter from which thread you call Start.
Here's an explanation of what's happening in your code: You're starting a Windows Forms timer on a non-UI thread. This kind of timer requires a message pump to be running on that thread so it can receive messages. Because it's a non-UI thread, there's no message pump. When you used the Dispatcher.Invoke method, you marshaled the creation of the timer back to the application's main UI thread, which made it work. But it is all quite redundant. If you want to keep the code as is, just replace the timer with a DispatcherTimer, and then you'll be able to remove the Invoke call.
Alternatively, if you're using .NET 4.5 you could use await/async to make this all much easier (be sure to call SomeMethod from the UI thread):
async Task SomeMethod(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.Run(() => DoAsyncStuff(), ct);
DoUIStuff();
await Task.Delay(TimeSpan.FromMinutes(1), ct);
}
}
MSDN can explain it for you:
Note The Windows Forms Timer component is single-threaded, and is
limited to an accuracy of 55 milliseconds. If you require a
multithreaded timer with greater accuracy, use the Timer class in the
System.Timers namespace.
Related
I have a WinForms application on .NET 3.5. In this form, the user triggers an operation which is executed in another thread (a BackgroundWorker to be precise) so as to not block the UI thread. I'm in MVP, so all this is being done by a presenter which interacts with an interface to the view (implemented by the Windows Form). So far so good.
I would like to introduce functionality whereby a timeout period is introduced for the background operation to complete before cancelling it. Sounds simple enough. But the background operation calls a single function on a third-party component which may never return, so the cancellation capabilities of the BackgroundWorker are of no use to me here. Also, the BackgroundWorker.RunWorkerCompleted allowed me to get back on the UI thread, so I need to wait for the timeout or success and be able to get back to my calling thread (namely the UI thread).
I tried this using a plain old Thread (which does support Abort()) and a Timer running on a second thread, but can't seem to get it to work quite right since Join() is blocking my UI thread despite the description stating that it will block "while continuing to perform standard COM and SendMessage pumping". Admittedly I assumed this implied that it would continue to process Windows Messages, which was not the case.
int timeoutInMsec = 10000;
Thread connectThread = new Thread(Connect);
Thread timerThread = new Thread(() =>
{
var timer = new System.Windows.Forms.Timer() { Interval = timeoutInMsec };
timer.Tick += (_s, _e) =>
{
timer.Stop();
if (connectThread.ThreadState == ThreadState.Running)
connectThread.Abort();
};
};
connectThread.Start();
timerThread.Start();
timerThread.Join();
connectThread.Join();
Based on this question, I tried removing the second timer thread and adding a ManualResetEvent and calling Set() when the timer ticked, or when the Connect method did indeed complete. Here, instead of Join I used WaitOne, but unfortunately this also blocks my UI thread. I also found this other question, which a CancellationTokenSource which unfortunately is not available in .NET 3.5.
So, how can I spin my worker up and be able to terminate it after a given amount of time in .NET 3.5, while at the same time be able to get back to the thread where I spun up the worker thread to execute a sort of OnCompleted handler?
Many thanks in advance!
PS: I don't have a lot of experience in multi-threaded programming in .NET, so I'm sorry if this is trivial.
If I understood your question correctly, the following algorithm should solve your problem:
As before, create a BackgroundWorker to do your background work.
In BackgroundWorker_DoWork,
create a new thread (let's call it the "third-party thread") to call your third-party library, and then
wait for the third-party thread to finish or the timeout to elapse. (*)
That way, your UI won't block, since only the Backgroundworker thread is waiting, not the main thread.
Now about the interesting part: How do you wait for the third-party thread to finish (the step marked with (*))?
My suggestion would be to simply use "loop waiting with sleep", i.e. (pseudo-code, you can use the Stopwatch class for the timeout):
do until (third-party thread has finished or x seconds have elapsed):
Thread.Sleep for 100ms
if third-party thread has not finished:
Abort it // we don't have another choice
else
Process the result
It's not best practice, but it's simple, it gets the job done and you can always replace it with fancy cross-thread-syncronization stuff (which is non-trivial to get right) once you got it all working.
It's useless to create a Forms.Timer on a non-gui thread. Don't create it on a separate thread. Why are you Joining the threads? The usage of Join is to block the current thread until the other thread is finished.
This is untested pseudo code, this is for example purpose.
public class Form1: Form1
{
private int timeoutInMsec = 10000;
private System.Windows.Forms.Timer _timer;
private Thread _connectThread;
public Form1()
{
_connectThread = new Thread(Connect);
_connectThread.Start();
_timer = new System.Windows.Forms.Timer() { Interval = timeoutInMsec };
_timer.Tick += (_s, _e) =>
{
_timer.Stop();
if (_connectThread.ThreadState == ThreadState.Running)
_connectThread.Abort();
};
};
}
private void Connected()
{
}
private void Aborted()
{
}
private void Connect()
{
try
{
DoConnect3rdPartyStuff();
this.Invoke(Connected);
}
catch(ThreadAbortException)
{
// aborted
this.Invoke(Aborted);
}
}
}
There is a piece of 3rd party API code, SomeWork(), that needs to run every 3 seconds to monitor some physical devices. I would of thought using using System.Timers.Timer and its Elapse event is asynchronous, but it lags my GUI operation every 3 seconds. I tried doing SomeWork() using Dispatcher.BeginInvoke yet I still experience the same lag on the GUI, even SomeWork() does not actually update any GUI and should not occupy the GUI thread.
private void StartTimerAtStartup()
{
System.Timers.Timer connTimer = new System.Timers.Timer();
connTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);
connTimer.Interval = 3000;
connTimer.Enabled = true;
}
private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Send, (ElapsedEventHandler)MyTimer_Elapsed, sender, e);
return;
}
// Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(
// () => SomeWork())
// );
SomeWork();
}
[EDIT1]
If I remove all Dispatcher and call SomeWork() directly then I get an exception that I cannot access this thread.
[EDIT2]
SomeWork() is a 3rd party API listening to physical devices and receiving packets, which does not touch the GUI. I tried various ways of doing the Dispatcher.BeginInvoke and I encounter the following, which I cannot understand. Why would using lamda lags the GUI but doing a delegate does not lag the GUI?
// This lags the GUI
Dispatcher.BeginInvoke(new Action( () => SomeWork() ));
// This does not lag the GUI. Application runs smooth,
// but I do not understand why
Dispatcher.BeginInvoke((Action)delegate () { SomeWork(); });
You call Dispatcher of GUI thread. Thus, BeginInvoke invokes async work to UI thread and you get your UI lagged.
Your timer fires Elapsed event in the different than UI thread. So you can just simply call your method in the event handler.
However, if you need to call your API strictly every 3 seconds than you need to either consider time that takes to execute SomeWork or do the job in separated thread. Then you can use tasks to achieve that.
Task.Factory.StartNew(SomeWork);
But in this case you will have to deal with possible race conditions and synchronize your work.
I have an Async DataGrid loading feature. Hence, i need to call WaitFor(). Here's that code:
WaitFor(TimeSpan.Zero, DispatcherPriority.SystemIdle);
And following are the 2 methods. Can someone explain what this methods are exactly doing?
public static void WaitFor(TimeSpan time, DispatcherPriority priority)
{
DispatcherTimer timer = new DispatcherTimer(priority);
timer.Tick += new EventHandler(OnDispatched);
timer.Interval = time;
DispatcherFrame dispatcherFrame = new DispatcherFrame(false);
timer.Tag = dispatcherFrame;
timer.Start();
Dispatcher.PushFrame(dispatcherFrame);
}
public static void OnDispatched(object sender, EventArgs args)
{
DispatcherTimer timer = (DispatcherTimer)sender;
timer.Tick -= new EventHandler(OnDispatched);
timer.Stop();
DispatcherFrame frame = (DispatcherFrame)timer.Tag;
frame.Continue = false;
}
You do not need any WaitFor(). Why waiting for something anyways? Just let the UI thread unfrozen and once data loaded the DataGrid will display them.
The methods you posted are doing the.... WaitFor mechanism. The method name explains it all :)
Here are few more details:
DispatcherTimer is a simple dumb Timer you might already know from basic C# just once tick method invoked it will be executed directly on UI thread, hence you do not need to care whether you are on UI thread or not. You always are :)
DispatcherTimer has a prority means if proprity set to high the tick invocation method will be called immediately after interval. If proprity is set to Background the tick method will be invoked when UI thread is not busy.
DispatcherFrame is the current scope you are in. Every displatcher operation has sort of scope. Each scope processes pending work items
Dispatcher.PushFrame is same as DoEvent() back when people used WinForms alot. To keep it simple with DoEvent you are forcing UI thread to do something.
To sum up you wait for things to get done in UI thread.
I hope this helps you any futher.
I want to repeat a function from the moment the program opens until it closes every few seconds.
What would be the best way to do this in C#?
Use a timer. There are 3 basic kinds, each suited for different purposes.
System.Windows.Forms.Timer
Use only in a Windows Form application. This timer is processed as part of the message loop, so the the timer can be frozen under high load.
System.Timers.Timer
When you need synchronicity, use this one. This means that the tick event will be run on the thread that started the timer, allowing you to perform GUI operations without much hassle.
System.Threading.Timer
This is the most high-powered timer, which fires ticks on a background thread. This lets you perform operations in the background without freezing the GUI or the main thread.
For most cases, I recommend System.Timers.Timer.
For this the System.Timers.Timer works best
// Create a timer
myTimer = new System.Timers.Timer();
// Tell the timer what to do when it elapses
myTimer.Elapsed += new ElapsedEventHandler(myEvent);
// Set it to go off every five seconds
myTimer.Interval = 5000;
// And start it
myTimer.Enabled = true;
// Implement a call with the right signature for events going off
private void myEvent(object source, ElapsedEventArgs e) { }
See Timer Class (.NET 4.6 and 4.5) for details
Use a timer. Keep in mind that .NET comes with a number of different timers. This article covers the differences.
There are lot of different Timers in the .NET BCL:
System.Timers.Timer
System.Threading.Timer
System.Windows.Forms.Timer
System.Web.UI.Timer
System.Windows.Threading.DispatcherTimer
When to use which?
System.Timers.Timer, which fires an event and executes the code in one or more event sinks at regular intervals. The class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
System.Threading.Timer, which executes a single callback method on a thread pool thread at regular intervals. The callback method is defined when the timer is instantiated and cannot be changed. Like the System.Timers.Timer class, this class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
System.Windows.Forms.Timer (.NET Framework only), a Windows Forms component that fires an event and executes the code in one or more event sinks at regular intervals. The component has no user interface and is designed for use in a single-threaded environment; it executes on the UI thread.
System.Web.UI.Timer (.NET Framework only), an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval.
System.Windows.Threading.DispatcherTimer, a timer that's integrated into the Dispatcher queue. This timer is processed with a specified priority at a specified time interval.
Source
Some of them needs explicit Start call to begin ticking (for example System.Timers, System.Windows.Forms). And an explicit Stop to finish ticking.
using TimersTimer = System.Timers.Timer;
static void Main(string[] args)
{
var timer = new TimersTimer(1000);
timer.Elapsed += (s, e) => Console.WriteLine("Beep");
Thread.Sleep(1000); //1 second delay
timer.Start();
Console.ReadLine();
timer.Stop();
}
While on the other hand there are some Timers (like: System.Threading) where you don't need explicit Start and Stop calls. (The provided delegate will run a background thread.) Your timer will tick until you or the runtime dispose it.
So, the following two versions will work in the same way:
using ThreadingTimer = System.Threading.Timer;
static void Main(string[] args)
{
var timer = new ThreadingTimer(_ => Console.WriteLine("Beep"), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
Console.ReadLine();
}
using ThreadingTimer = System.Threading.Timer;
static void Main(string[] args)
{
StartTimer();
Console.ReadLine();
}
static void StartTimer()
{
var timer = new ThreadingTimer(_ => Console.WriteLine("Beep"), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
}
But if your timer disposed then it will stop ticking obviously.
using ThreadingTimer = System.Threading.Timer;
static void Main(string[] args)
{
StartTimer();
GC.Collect(0);
Console.ReadLine();
}
static void StartTimer()
{
var timer = new ThreadingTimer(_ => Console.WriteLine("Beep"), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
}
When we use System.Threading.Timer, then is the method executed on the thread that created the timer? Or is ir executed in another thread?
class Timer
{
static void Main()
{
TimerCallback tcall = statusChecker.CheckStatus;
Timer stateTimer = new Timer(tcb, autoEvent, 1000, 250);
}
}
class StatusChecker
{
public void CheckStatus(Object stateInfo)
{
}
}
My question is if the method called by the timer delegate (CheckStatus) is executed in main thread or is it executed in another thread?
System.Threading.Timer will execute its work on another thread in the thread pool.
System.Windows.Forms.Timer will execute on the existing (GUI) thread.
The docs say the following:
The method specified for callback should be reentrant, because it is called on ThreadPool threads.
So the callback will almost certainly be on another thread.
Of course, if you launch the timer from a ThreadPool thread, there's a chance it might execute on the same thread, but no guarantee.
MSDN States:
Use a TimerCallback delegate to specify the method you want the Timer to execute. The timer delegate is specified when the timer is constructed, and cannot be changed. The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.
Hence, in your example, timer delegate (CheckStatus) would be executed in an seperate thread.