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.
Related
if I set a timer like this:
var MyTimer = new Timer(RunTask, AutoEvent, 1000, 2000);
is it guaranteed that RunTask will always be run on the same thread?
all my tests seem to indicate that it is the case, but is it a guarantee or luck?
this is quite important since I need to store variables that persist call to call and I'm currently using the [ThreadStatic] attribute on them.
I know that if the call back is holding the thread longer than the timer delay, the timer will do another callback on another thread; so I narrow the question to the case where there are no parallel runs (I block teh timer during the callback).
The System.Threading.TimerCallback delegate allows you to pass a context object to the callback method. You can use this context object to pass the state that you need in the callback handler. This way it wont matter what thread you are called back on, as you won't need to use ThreadStatic.
The state argument that you pass to the Timer constructor will be passed to the callback method.
To answer your question, no there is no such thing as a "reserved" thread for the TimerCallback. The event is scheduled on a ThreadPool and there is no guarantee that the next tick will happen on the same thread, even tho it is possible.
A simple test illustrates this:
myTimer = new System.Threading.Timer(timer_Elapsed, null, 0, Timeout.Infinite);
static void timer_Elapsed(object state)
{
Thread.Sleep(100);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
myTimer.Change(100, Timeout.Infinite);
}
And the results:
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);
}
}
}
When I started main thread I also started a second thread, but the second thread still waits for the main thread. I expected that when I started a new thread it would go do work without being connected to the main thread. So why does panel1 become visible after the main thread finishing its job?
private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(threadUI));
thread.Start();
// This class is loading something from the server on the main thread
excel.get_data_from_excel(comboBox1.SelectedItem.ToString(), this);
}
private void threadUI()
{
if (panel1.InvokeRequired)
{
panel1.Invoke(new newDelegate(threadUI));
}
else
{
panel1.Visible = true;
}
}
The Invoke method will not return until the main thread executes the delegate. If you want the background thread to continue without waiting for the main thread, use BeginInvoke instead.
However, be aware that only one thing can be occurring on the main thread. You can call Invoke or BeginInvoke, but the delegate won't be processed until the main thread is idle. That is, if get_data_from_excel takes a long time, your panel1.Visible=true will not take effect until get_data_from_excel completes, comboBox1_SelectedIndexChanged_1 returns, and the main thread becomes idle.
If you truly want to make these things "parallel", you must execute get_data_from_excel in a background thread.
You're doing long running non-UI work in the UI thread.
The second thread that you create is doing nothing but calling Invoke and doing a bit of work. What Invoke does is run some code in the UI thread, which is currently busy doing some non-UI work. It won't be scheduled to run until after that work finishes.
What you should do is do that long running non-UI work in another thread, rather than the UI thread.
It looks like you're confused about Invoke().
Invoke() is used to queue up a delegate for the thread that displays panel1. However, Invoke() blocks UNTIL that delegate has run to completion. Therefore, you have your second thread blocking at Invoke().
If you would like to have an action run on the main thread, while calling it from the second thread WITHOUT blocking... then use BeginInvoke(). It will queue up the delegate and then return immediately.
Servy's Comment
Servy brings up a good point. Whats the point of the second thread, if it is just going to immediately call the first? There isn't any need to create a second thread if you are just going to immediately adjust a control's property.
But it looks like you are grabbing data from excel. That section of code should be in the second thread... and then with it's output use BeginInvoke().
if i use code just like this it also waiting for the complete next
line finishing its job
private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
panel1.Visible = true;
excel.get_data_from_excel(comboBox1.SelectedItem.ToString(), this);
}
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.
Is that possible not not block winForm using WaitHandle.WaitAll(waitHandles) but just set another thread which will fire when get complate signal from WaitHandle.WaitAll?
I would not use WaitHandle.WaitAll. There are a couple of problems with this approach.
There is a 64 handle limit.
It cannot be used on an STA thread.
It promotes patterns that depend on the creation of multiple WaitHandle instances which obviously consume resource.
Instead, I typically use the CountdownEvent class when I want to wait on multiple events. Now, the problem you will have with that is that it still requires you to call Wait on some thread which is exactly what you are trying to avoid. The standard mechanism to avoid making a blocking call is to use the ThreadPool.RegisterWaitForSingleObject method. But, unfortunately that takes a WaitHandle and CountdownEvent does not inherit from that class.
The solution is to create your own CountdownWaitHandle class that can be used in the ThreadPool.RegisterWaitForSingleObject method. This approach will allow you to specify a callback delegate that will be executed once the WaitHandle is signaled.
Here is the most basic implemenation for the CountdownWaitHandle class. You will have to add all of the necessary harding code yourself, but this will get you started.
public class CountdownWaitHandle : WaitHandle
{
private int m_Count = 0;
private ManualResetEvent m_Event = new ManualResetEvent(false);
public CountdownWaitHandle(int initialCount)
{
m_Count = initialCount;
}
public void AddCount()
{
Interlocked.Increment(ref m_Count);
}
public void Signal()
{
if (Interlocked.Decrement(ref m_Count) == 0)
{
m_Event.Set();
}
}
public override bool WaitOne()
{
return m_Event.WaitOne();
}
}
The idea here is that instead of using many different WaitHandle instances you use a single CountdownWaitHandle instance. Initialize the instance with the desired count and then call Signal to decrement the count. Once the count gets to zero the WaitHandle will go into the signaled state. So instead of calling Set on multiple WaitHandle instances and blocking with WaitHandle.WaitAll you now call Signal on this one instance and block by calling WaitOne. And again, you can push off the blocking call to the thread pool by using TheadPool.RegisterWaitForSingleObject which will invoke a callback when the WaitHandle is signaled.
You can call WaitAll in a background thread, then call BeginInvoke to move back to the UI thread.
Have a look at ManualResetEvent. Using this you can set the event when your thread has finished, and any other thread can either wait on this event, or check to see if it is in the signalled state.
ManualResetEvent ev = new ManualReserEvent();
while(Users["user428547"].AcceptanceRate == 0)
{
// this might take a long time
};
ev.Set(); // done, he accepted an answer.
Perhaps you could start another thread yourself, and call WaitHandle.WaitAll yourself on that thread? If you are not starting too many other threads, this should work fine.