Timer Spawn By Task And Task Spawn By Timer - c#

I can't quite explain to myself in clear terms why a Task spawn by a Timer works just fine but a Timer spawn by a Task does NOT.
All relevant code is included below so you can easily reproduce it.
Form.cs:
private void Form1_Load(object sender, EventArgs e)
{
ProcessDelayList list = new ProcessDelayList();
foreach (ProcessDelay p in list)
{
//this works
p.Start();
//this does NOT work
//Task.Factory.StartNew(() => p.Start());
}
}
ProcessDelayList.cs:
public class ProcessDelayList : List<ProcessDelay>
{
public ProcessDelayList()
{
Add(new ProcessDelay("Process 1", 2000));
Add(new ProcessDelay("Process 2", 4000));
Add(new ProcessDelay("Process 3", 6000));
Add(new ProcessDelay("Process 4", 8000));
Add(new ProcessDelay("Process 5", 10000));
}
}
ProcessDelay.cs:
public class ProcessDelay
{
private string name;
private int delay;
private Timer timer;
public ProcessDelay(string name, int delay)
{
this.name = name;
this.delay = delay;
}
public void Start()
{
timer = new Timer();
timer.Interval = delay;
timer.Tick += timer_Tick;
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
//these work either way, as long as the task
// is NOT spawn in the main loop.
//TimerProc();
TimerProcTask();
}
private void TimerProcTask()
{
Task.Factory.StartNew(() => TimerProc());
}
private void TimerProc()
{
timer.Stop();
MessageBox.Show(name, delay.ToString());
}
}

Ah, Timers. There are four of them in .NET, each with slightly different behaviors. You are using System.Windows.Forms.Timer.
This timer uses the Win32 message queue to fire timer events (WM_TIMER). The thread that creates the timer is the one on which the callback method (timer_Tick) is executed. The thread needs a message pump in order for the timer to execute.
Telling the task to run on the current SynchronizationContext will make it work:
Task.Factory.StartNew(() => p.Start(),
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext());
This actually marshals the call to happen on the UI thread, though, so it seems sort of pointless to me, if all you're doing is calling the p.Start() method anyway (pretty much acts single threaded).
Note the remarks section of the System.Windows.Forms.Timer class:
This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available and always operate from the same thread, or marshal the call onto another thread.
You can use System.Threading.Timer (or the System.Timers.Timer wrapper of this class) if you want your timer calls to actually execute on a separate thread. If you need your timer callback to update the UI, you will need to marshal that UI update call to the UI thread. However, you can make sure that any processing-intensive work is done on a separate thread, and only the smallest amount of code (e.g. actual updating of the controls) is done on the UI thread to keep it responsive.

Related

Threadsafe logging not working with Task or Thread in debugger

I try to log text messages from a Task or Thread to a textbox on my form. For that i use Invoke and InvokeRequired methods to syncronize with the main thread, as i can be found in many examples on the internet. See LogMessage_Delegate and LogMessage_Threadsafe below. When i close the app, a boolean flag finished is set to true and the task/thread should stop the work.
This all works fine until i set a breakpoint on the first line of the Form1_FormClosing event handler (finished = true;). Then i see only the console message "LogMessage InvokeRequired", but no corresponding "LogMessage" and the app is hanging.
If i comment out the LogMessage_Threadsafe call in Work (only console messages), then it works again. The app is closing, as expected.
So, can anybody explain this behavior to me? I can find no reason for it.
Please note, i do the flagging in the Form1_FormClosing event handler, so the form is still alive and working.
namespace MultiThreadedTest
{
public partial class Form1 : Form
{
//************************************************************
// Fields
Thread worker = null;
Task task = null;
bool finished = false;
//************************************************************
// Constructor
public Form1()
{
InitializeComponent();
worker = new Thread(Work);
worker.Start();
//task = Task.Factory.StartNew(Work);
}
//************************************************************
// Helper methods
public void LogMessage(string sMessage)
{
LogTextBox.Text += sMessage + Environment.NewLine;
}
/// <summary>
/// Threadsafe wrapper for LogMessage
/// </summary>
delegate void LogMessage_Delegate(string sMessage);
public void LogMessage_Threadsafe(string sMessage)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.InvokeRequired)
{
Console.WriteLine("LogMessage InvokeRequired");
LogMessage_Delegate callback = new LogMessage_Delegate(LogMessage_Threadsafe);
this.Invoke(callback, new object[] { sMessage });
}
else
{
Console.WriteLine("LogMessage");
LogMessage(sMessage);
}
}
//************************************************************
// Commands
void Work()
{
while (!finished)
{
Console.WriteLine("Tread/Task Waiting...");
LogMessage_Threadsafe("Tread/Task Waiting...");
Thread.Sleep(1000); // Wait a little...
}
Console.WriteLine("Thread/Task Done");
}
//************************************************************
// Events
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
finished = true;
if (worker != null) worker.Join();
if (task != null) Task.WaitAll(task);
Console.WriteLine("App Done");
}
}
}
You don't need to use raw threads since .NET 4 with the introduction of Tasks. Invoke wasn't needed either but became obsolete since .NET 4.5 with the introduction of async/await. 4.5 also introduced thread-safe progress reporting and cancellation with the IProgress< T> inteface and Progress< T> implementation, as explained in Async in 4.5: Enabling Progress and Cancellation in Async APIs.
Progress<T> calls its delegate on the thread it was created on, in this case the UI thread. You can pass the interface to any background method (task, thread method etc) and use it to report progress.
Given that the earliest supported .NET version is 4.5.2, you can assume these classes will always be available. BTW, TLS 1.2 support was added in 4.5.2 so any holdouts are forced to upgrade already, as they find they can't connect to GMail or other services that demand TLS 1.2.
Your code can be simplified a lot by using these classes. A quick&dirty form with a background timer and thread-safe reporting is the following:
public partial class Form1 : Form
{
System.Threading.Timer _timer;
IProgress<string> _progress;
public Form1()
{
InitializeComponent();
_progress = new Progress<string>(msg => textBox1.Text += msg + "\r\n");
_timer = new System.Threading.Timer(theCallback);
}
private async void theCallback(object state)
{
for (int i = 0; i < 5; i++)
{
await Task.Delay(100);
_progress.Report($"Boo {i}");
}
}
private void Form1_Load(object sender, EventArgs e)
{
_timer.Change(0, 10000);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_timer.Dispose();
_timer = null;
_progress = null;
}
}
UPDATE
As for why the original code blocks, it's because Thread.Join() is called from the UI thread in Form.Closing. If the background thread tries to call Invoke to marshal a call to the UI thread, it will get blocked itself precisely because the UI thread is blocked.
This can be avoided by calling BeginInvoke instead of Invoke(). This was the typical way to handle callbacks into the UI thread before .NET 4.
The blocking behaviour can be seen in the Parallel Stacks debugger window (Debug / Windows / Parallel Stacks). When the form deadlocks, two stacks appear, one in the Form.Closing method and one in the LogMessage_Threadsafe method
If you're paused at a breakpoint in the UI thread, calls marshaled to the UI thread via Invoke won't execute, because they run on the UI thread, which is paused.
But judging from your comment, that doesn't seem to be the issue. So I would guess the problem is that, by pausing at that breakpoint, you've allowed the background thread to get into a state where it's blocking on Invoke(), and then you're trying to join that background thread, which will block until the Invoke completes, which will never happen.
As a separate issue, if you're accessing finished from multiple threads, you need to surround the reads and writes with lock blocks to ensure thread safety.

C# how to stop thread in time?

I have an user control which include timer. When timer event run, it will call some threads.
User Control
class MyControl
{
public Timer iTime
{
get;
set;
}
Timer tmr;
public MyControl
{
tmr = new Timer();
}
// Some Properties
}
}
Main Form
class MyForm
{
Thread thd;
MyControl cls = new MyClass();
cls.iTime.Tick += new EventHandler(iTime_Tick);
void iTime_Tick(object sender, EventArgs e)
{
thd = new Thread(delegate() { doWork(1); });
thd.Start();
thd = new Thread(delegate() { doOtherJob(); });
thd.Start();
}
delegate void notif(int Param1);
void Job(int Param1)
{
if (this.InvokeRequired)
{
notif handler = new notif(notifParam);
this.Invoke(handler, new object[] { Param1 });
}
else
{
// Other Process
}
}
private void Logout()
{
cls.iTime.Stop();
cls.iTime.Enabled = false;
cls.iTime.Tick -= new EventHandler(iTime_Tick);
thd.abort();
thd.join();
}
}
How to terminate thread in timer ? When I unsubscribe timer event even close form, the threads still run.
Disposing the form has no effect on your threads.
Your code is clearly incomplete (for example MyControl cls = new MyClass();, and we have no idea what doWork or doOtherJob are), but I suspect part of the problem is that you only have a single thread variable.
Every time the timer ticks, you do thd = new Thread twice. If your timer ticks ten times then thd is pointing at your most recent thread, but there are potentially 19 other threads still running, and any of those might be keeping your application alive.
One thing that might help is explicitly setting .IsBackground to true on the threads you create, since that will encourage them to terminate when your UI thread closes. However, I'd advise that creating this many threads in this way is likely not an efficient model, and you'd be better off revising your design to run just one or two worker threads, instead of kicking of dozens.

Interacting between two threads

I am working on a winform application, and my goal is to make a label on my form visible to the user, and three seconds later make the label invisible. The issue here is timing out three seconds. I honestly do not know if this was the correct solution to my problem, but I was able to make this work by creating a new thread, and having the new thread Sleep for three seconds (System.Threading.Thread.Sleep(3000)).
I can't use System.Threading.Thread.Sleep(3000) because this freezes my GUI for 3 seconds!
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
// Once three seconds has passed / thread has finished: lbl_authenticationProcess.Visible = false;
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
}
So, back to my original question. How can I determine (from my main thread) when the new thread has completed, meaning three seconds has passed?
I am open to new ideas as well as I'm sure there are many.
Right now, you are blocking the entire UI thread in order to hide a label after 3 seconds. If that's what you want, then just user Thread.Sleep(3000) from within the form. If not, though, then you're best off using a Timer:
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 3000;
timer.Tick += (s, e) => { this.lbl_authenticationProcess.Visible = false; timer.Stop(); }
timer.Start();
After 3 seconds, the label will disappear. While you're waiting for that, though, a user can still interact with your application.
Note that you must use the Forms version of Timer, since its Tick event is raised on the UI thread, allowing direct access to the control. Other timers can work, but interaction with the control would have to be Invoke/BeginInvoked.
Did you try to use Timer
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 3000;
t.Start();
t.Tick += new EventHandler(t_Tick);
void t_Tick(object sender, EventArgs e)
{
label.Visible = false;
}
You really don't need to synchronize anything. You just need a new thread, with a reference to your label. Your code is actually pretty close:
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
lbl_authenticationProcess.Visible = true;
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
if (lbl_authenticationProcess.InvokeRequired) {
lbl_authenticationProcess.Invoke(new SimpleCallBack(makeInvisible));
} else {
makeInvisible();
}
}
private void makeInvisible()
{
lbl_authenticationProcess.Visible = false;
}
So, when someVoid() is called, the message on the label is set, the label is made visible. Then a new thread is started with the newThread_restProgram() as the body. The new thread will sleep for 3 seconds (allowing other parts of the program to run), then the sleep ends and the label is made invisible. The new thread ends automatically because it's body method returns.
You can make a method like so:
public void SetLbl(string txt)
{
Invoke((Action)(lbl_authenticationProcess.Text = txt));
}
And you would be able to call it from the second thread, but it invokes on the main thread.
If you're using .NET 3.5 or older, it's kinda a pain:
private void YourMethod()
{
someLabel.BeginInvoke(() =>
{
someLabel.Text = "Something Else";
Thread thread = new Thread(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
thread.Start();
});
}
That should stop you from blocking the UI.
If you're using .NET 4+:
Task.Factory.StartNew(() =>
{
someLabel.BeginInvoke(() => { someLabel.Text = "Something" });
}).ContinueWith(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
If you are willing to download the Async CTP then you could use this really elegant solution which requires the new async and await keywords.1
private void async YourButton_Click(object sender, EventArgs args)
{
// Do authentication stuff here.
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
await Task.Delay(3000); // TaskEx.Delay in CTP
lbl_authenticationProcess.Visible = false;
}
1Note that the Async CTP uses TaskEx instead of Task.
You can use an AutoResetEvent for your thread synchronization. You set the event to signalled when your secondary thread has woken from it's sleep, so that it can notify your main thread.
That means though that your main thread waits for the other thread to complete.
On that note, you can use SecondThread.Join() to wait for it to complete in your main thread.
You do either of the above, but you don't need to do both.
As suggested in the comments, having a UI thread sleep is not generally a good idea, as it causes unresponsiveness for the user.
However if you do that, you might as well just sleep your main thread and get rid of the extraneous need of the second thread.
I'm not exactly sure this is the right way to do it, but to answer your question, you have to use the Join() function.
public void CallingThread()
{
Thread t = new Thread(myWorkerThread);
t.Join();
}
public void WorkerThread()
{
//Do some stuff
}
You can also add a timeout as parameter to the function, but you don't need that here.

timer inside thread

My Aim: I am having a credit card wait window. I will call a function from the client to wait for the credit card swipe. In order to avoid the program getting stuck while waiting for the credit card . I am using a delegate to run a timer. The delegate will call a timer. The timer periodically checks for the presence for the card. If it found a card it will a callback/delegate assigned by the client.
the code is given below, my questions are
1) Will the _timer_Elapsed will get called within the thread so that it will add minimum overhead to the ui window?
2) How can i call the callback/event of the base class from the timer function. I have written a protected method which will call the event/delegate in the base class. I need to call the protected method from the timer function( which is inside a delegate in the derived class.)?
Wait wait = delegate()
{
_timer = new Timer(3000); // Set up the timer for 3 seconds
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true; // Enable it
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
// if(CheckCardsPresence())
{
//RaiseEvent()
//KillTimer()
}
//else
{
// do nothing. wait more
}
}
};
wait.Invoke();
No, the timer callback will not execute on the delegate-thread.
How could it? A timer cannot 'break in' on a thread, that thread has to poll.
This delegate-thread will terminate immediately after starting the timer. Which means you don't need this thread at all. Unless there is code not shown.
When you use a System.Threading.Timer the callback will be pushed onto the Threadpool.
To the second question (do try to ask only 1 question at a time)
A protected member should be accessible from an anonymous (embedded) method. Do you have a concrete problem?
From the MSDN documentation (sorry I got the wrong class the first time around)
This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available.
This is a roundabout way of saying that the event will be raised on the UI thread / message pump, i.e. the answer to your first question is yes as long as by "the thread" you mean "the UI thread".
I don't really understand your second question - what base class are you talking about?
First, that code will not compile. You cannot declare a named method from within another method. You can, however, declare an anonymous method or lambda expression and then assign it to a delegate reference.
There may not be any need to do asynchronous polling of the credit card device. You might be able to use a System.Windows.Forms.Timer and perform the polling from the Tick event which runs on the UI thread. This would be acceptable if the CheckCardsPresence is a quick operation.
public class CreditCardWaitWindow : Form
{
private System.Windows.Timer timer = new System.Windows.Timer();
private void Form_Load(object sender, EventArgs args)
{
timer.Tick += OnTick;
timer.Interval = 3000;
timer.Start();
}
private void OnTick(object sender, EventArgs args)
{
if (CheckCardsPresence())
{
RaiseEvent();
timer.Stop();
}
}
}
If polling the credit card device is a time consuming operation then you will want to perform this operation on another thread to avoid blocking the UI.
public class CreditCardWaitWindow : Form
{
private System.Timers.Timer timer = new System.Timers.Timer();
private void Form_Load(object sender, EventArgs args)
{
timer.Elapsed += OnElapsed;
timer.Interval = 3000;
timer.AutoReset = false;
timer.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs args)
{
if (CheckCardsPresence())
{
Invoke(
(MethodInvoker)(() =>
{
RaiseEvent();
}), null);
}
else
{
timer.Start();
}
}
}
Here is a cleaner implementation using a Task.
public class CreditCardWaitWindow : Form
{
private void Form_Load(object sender, EventArgs args)
{
Task.Factory.StartNew(
() =>
{
while (true)
{
Thread.Sleep(3000);
if (CheckCardsPresence()) break;
}
}, TaskCreationOptions.LongRunning).ContinueWith(
() =>
{
RaiseEvent();
}, TaskScheduler.FromCurrentSychronizationContext());
}
}
And to really top things off you could do this in C# 5.01 with the new await keyword. I am not sure it can get anymore succinct than that!
public class CreditCardWaitWindow : Form
{
private async void Form_Load(object sender, EventArgs args)
{
while (!CheckCardsPresence()) await Task.Delay(3000);
RaiseEvent();
}
}
1C# 5.0 has not been released yet.

Telling the timer object to invoke its "Elapsed" event asynchronously

There are times in my application, when I need to invoke my timer manually.
I've tried the following:
int originalInterval = t.Interval;
t.Interval = 0;
t.Interval = originalInterval;
but it wasn't consistent.
I've created a new timer, inheriting from System.Timers.Timer, and exposed a "Tick" method - but the problem was that the "Elapsed" event then fired synchronously.
When I implemented the "Tick" with a new Thread - the results were, again, not consistent.
Is there a better way to implement it?
I once had the same problem, so I used the AutoResetEvent to know if the Elapsed was invoked successfully:
/// <summary>
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course)
/// </summary>
public class TickableTimer : System.Timers.Timer
{
public new event ElapsedEventHandler Elapsed;
private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true);
public TickableTimer()
: this(100)
{
}
public TickableTimer(double interval)
: base(interval)
{
base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed);
}
public void Tick()
{
new System.Threading.Thread(delegate(object sender)
{
Dictionary<string, object> args = new Dictionary<string, object>
{
{"signalTime", DateTime.Now},
};
TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args));
}).Start();
this.m_autoResetEvent.WaitOne();
}
void TickableTimer_Elapsed(object sender, ElapsedEventArgs e)
{
m_autoResetEvent.Set();
if (this.Elapsed != null)
this.Elapsed(sender, e);
}
}
It feels like you should look at your design a bit. Typically I try to avoid having the event handler method contain the actual work being done, but I rather try to let it be just a trigger, calling some other method that performs the work. That way you can invoke that other method from anywhere else as well:
private void Timer_Tick(object sender, EventArgs e)
{
new Thread(MethodThatDoesTheWork).Start();
}
private void MethodThatDoesTheWork()
{
// actual work goes here
}
Now, you can invoke MethodThatDoesTheWork from anywhere else within the class (either synchronously or asynchronously using a separate thread).
Alternatively, if MethodThatDoesTheWork should always be an asynchronous call, you can spawn the thread inside that method instead:
private void MethodThatDoesTheWork()
{
new Thread(() =>
{
// work code goes here
}).Start();
}
In these samples I have manually created threads. You can use that approach, the ThreadPool, Task or whatever other method of calling code asychronously, whichever fits best in your context.
Normally you shouldn’t need to fire a timer manually — you can always just run the event itself in a new thread. By and large, that’s basically what the timer does, and since you want to fire it manually, you don’t need the timer (for that manual invocation).
You didn’t specify any details as to what you mean by “not consistent”. The following should normally work:
Thread thread = new Thread(myDelegate);
thread.Start();
Of course, myDelegate can be a lambda in case you need to pass parameters:
Thread thread = new Thread(() => myMethod(param1, param2));
thread.Start();

Categories