C# BackgroundWorker Parallel Call to DoWorkEventHandler - c#

Here is my situation :
I have a ThreadManager launching BackgroundWorkers; I subscribe to the doWork event to Log stuff in it. I also subscribo to the doWork event in the BackgroundWorker itself to process stuff.
Well, The first subscription raises the event way after the second one was raised.
class ThreadManager
{
//(...)
for (int i = 0; i<100; i++)
{
myWorker wk = new myWorker();
wk.DoWork += new DoWorkEventHandler(wk_DoWork);
}
//(...)
public void wk_DoWork(object sender, DoWorkEventArgs e)
{
Console.Out.Write("PONG");
//(...) Workers Management logic (Pooling, priority, etc.)
}
}
internal class myWorker : : BackgroundWorker
{
//(...)
DoWork += new DoWorkEventHandler(DoMe);
//(...)
void DoMe(object sender, DoWorkEventArgs e)
{
Console.Out.Write("PING");
//(...) Run a 2-3mn file reading process
}
}
For some reason, I am getting all "Pings" in a row, and start getting Pongs only a few minutes after.
Is there something I am missing here ?
EDIT : I do not use "Console" per se, but asynchronous loggers (that was for the example). I have been careful to watch the debug process at the "PONG" line, and it is not hit way after the "PING"s has been launched.
MY SOLUTION :
This is exactly the extra code I was hoping to avoid, but I could'nt cut the pain finally.
So here it is, for those having the same issu and stumbling on this post :
class ThreadManager
{
//(...)
for (int i = 0; i<100; i++)
{
myWorker wk = new myWorker();
wk.StartedEvent += new myWorker.startDelegate(wk_Started);
}
//(...)
public void wk_Started(params-if-needed)
{
Console.Out.Write("PONG");
//(...) Do Stuff
}
}
internal class myWorker : BackgroundWorker
{
public delegate void startDelegate(string ID);
public event startDelegate StartedEvent;
protected override void OnDoWork(DoWorkEventArgs e)
{
StartedEvent(ID); //put whatever parameter suits you or nothing
base.OnDoWork(e);
e.Result = e.Argument;
Console.Out.Write("PING");
//(...) Do Stuff
}
}

You are missing the following:
The subscribers to the DoWork event are not called in parallel but in a serial manner, i.e. first your handler with PING and after that the handler with PONG. So, when the PING handler takes 3 minutes, the PONG handler will be executed three minutes after you called RunWorkerAsync.

DoWork is a normal event, and with multicast, it's a sequential call-chain, and BackgroundWorker does not change that.
In short, it's not typical to hang multiple event handlers off of that event.
So yes, it's perfectly natural, since you specifically mention in your comments that the first event handler runs for 2-3 minutes, then yes, the second event handler will start a few minutes later.

As far as I know, Console.Out.Write is buffered. Try WriteLine.

This might be unrelated, but it's recommended to override OnXXX methods in derived classes rather then subscribe to own events. Thus,
class MyWorker : BackgroundWorker
{
protected override void OnDoWork(...) { .... }
}
And do not forget to call base.OnDoWork().

Related

Update process from within method called by backgroundworker c#

I have an application with a gui and a Rich Text Box where I output what the program is currently doing since data processing can be quite long.
I tried two approaches for that:
1 In the Backgroundworker method I can just call the following code fine:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
Whereas I cannot use Form1.Processchange(); in the helper class due to the non static context
2 Therefore I tried to create my very first eventhandler.
The Idea was that helper.UpdateConsole() would raise an event
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
to which the Backgroundworker listens and then calls Processchange from its context
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks();
Helper helper = new Helper();
helper.OnConsoleUpdate += Processchange;
task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
//MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
GlobalVar.next = false;
backgroundWorker1.ReportProgress(1);
while (GlobalVar.next == false)
{
helper.TimeBreaker(100,"ms");
}
}
Unfortunately this was was not successful. As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work.
Edit: the OnConsoleUpdate() == null as shown on the screenshot below
event = null
The helper is in another class file "helpers" which might be important for a solution.
i hope you guys can help me out.
Welcome to SO!
A few things immediately jump to mind.
First, let's get the event issue out of the way. You've got the correct approach - you need an event and method to call it, but that method should check if the event is null.
Basically, do this:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
The above makes use of ?, a null-condition operator. You can read more about it on this MSDN page.
Second thing... it's unclear what your background worker actually IS. It sounds like it's some kind of custom class you crated? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true). And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own.
Here's how you can use the standard .NET BackgroundWorker:
System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
void StartBackgroundTask()
{
worker.DoWork += worker_DoWork;
//if it's possible to display progress, use this
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
//what to do when the method finishes?
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
//start!
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
//perform any "finalization" operations, like re-enable disabled buttons
//display the result using the data in e.Result
//this code will be running in the UI thread
}
//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
public string OperationDescription { get; set; }
public int CurrentResult { get; set; }
//feel free to add more stuff here
}
void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
//display the progress using e.ProgressPercentage or e.UserState
//this code will be running in the UI thread
//UserState can be ANYTHING:
//var data = (ProgressData)e.UserState;
}
void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//this code will NOT be running in the UI thread!
//you should NOT call the UI thread from this method
int result = 1;
//perform calculations
for (var i = 1; i <= 10; i++)
{
worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
result *= i;
}
e.Result = result;
}
Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage.
There's one more worrisome thing in your code.
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks(); //<- you create a task
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}
Do note that events, unless made static, aren't global. So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this:
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above

How to make a timer that redo the event programmatically?

So I want to perform some button clicks say every in 10 second, and here is my code:
using System;
using System.Timers;
public class Main : Form {
public Main() {
InitializeComponent();
// add timer to do button clicking every 10 seconds
double elapse = 10000;
System.Timers.Timer timer2 = new Time(elapse);
timer2.Elapsed += new ElapsedEventHandler(ResetEvent);
timer2.AutoReset = true;
timer2.Start();
}
private void ResetEvent(object source, ElapsedEventArgs e) {
try {
Refresh_Button.PerformClick();
Process_Button.PerformClick();
} catch { }
}
private void Refresh_Button_Click(object sender, EventArgs e) {
// some code
}
private void Process_Button_Click(object sender, EventArgs e) {
// some code
}
}
However, it doesn't work. Is there anything wrong with the code? How can I make it works?
The problem is accessing UI thread illegally in Elapsed event of System.Timers.Timer.
You are calling Refresh_Button.PerformClick(); in Elapsed event of timer that cause an cross thread exception that you are hiding it.
To access UI thtread and call PerformClick() method of Refresh_Button:
Refresh_Button.Invoke(new Action(() => { Refresh_Button.PerformClick(); }));
Also you can use System.Windows.Forms.Timer instead and handle Tick event and call Refresh_Button.PerformClick(); manually.
Note:
Don't hide exceptions. If you hide exceptions, such problems will hide and finding them will be really hard.
It's better to put the logic a method and instead of calling PerformClick, call that method.
If you don't need a different thread, System.Windows.Forms.Timer whould be enough.

correct way to re-call backgroundworker

As in title, I have some bgw I want to call on every button press.
Is this code correct ?
private static BackgroundWorker bgw = null;
private void bttn_Click(...)
{
if(!bgw.IsBusy)
doSomeWorkInBg();
else
MessageBox.Show("Slow down a bit");
}
private void doSomeWorkInBg()
{
if (bgw == null)
{
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
}
bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// do some work that takes time
}
Or maybe I should add RunWorkerCompleted event with "bgw = null;" code or something like that?
You should avoid making your bgw static, because you are using it in non-static context.
When I need to re-run the worker frequently based on the UI event, this is the construct that I usually use:
bool ShouldRunWorkedASAP;
private void bttn_Click(...){
ShouldRunWorkedASAP=true;
if (!bgw.IsBusy) bgw.RunWorkerAsync();
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
while (ShouldRunWorkedASAP) {
ShouldRunWorkedASAP=false;
// do some work that takes time
}
}
This assumes that the worked is instantiated in the class constructor. Basically this code sets the flag that the worker should run ASAP whenever the UI event occurred, then tries to run the worker. If it is already running - then the while() loop inside the worker implementation will schedule the job for the next run as soon as it completes.
This code does not ensure that the worker will run exactly the number of times the user presses the button, not sure if in your case this is required or not.

How to raise an event from an object that uses a timer back to the UI thread

I have an object that uses a timer to occasionally poll for a resource and then raises an event whenever the poll finds something of note. I have looked at several other examples but can't seem to find a method to marshall the event back to the UI thread without extra code on the event handler on the UI thread. So my question is:
Is there any way to hide this extra effort from the users of my object?
For the purpose of discussion I will include a trivial example:
Imagine I have a form with 1 richtextbox:
private void Form1_Load(object sender, EventArgs e)
{
var listener = new PollingListener();
listener.Polled += new EventHandler<EventArgs>(listener_Polled);
}
void listener_Polled(object sender, EventArgs e)
{
richTextBox1.Text += "Polled " + DateTime.Now.Second.ToString();
}
Also I have this object:
public class PollingListener
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
public event EventHandler<EventArgs> Polled;
public PollingListener()
{
timer.Elapsed +=new System.Timers.ElapsedEventHandler(PollNow);
timer.Start();
}
void PollNow(object sender, EventArgs e)
{
var temp = Polled;
if (temp != null) Polled(this, new EventArgs());
}
}
If I run this, as expected it yields the exception
"Cross-thread operation not valid: Control 'richTextBox1' accessed
from a thread other than the thread it was created on"
This makes sense to me, and I can wrap the event handler method differently as so:
void listener_Polled(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() => { UpdateText() }));
}
void UpdateText()
{
richTextBox1.Text += "Polled " + DateTime.Now.Second.ToString();
}
But now the user of my object has to do this for any event that is raised from the timer event in my control. So, is there anything I can add to my PollingListener class that doesn't change the signature of it's methods to pass in extra references that would allow the user of my object to be oblivious of the marshaling event in the background to the UI thread?
Thanks for any input you may have.
Added after comment:
You would need to pickup some latent detail that you can exploit to be able to accomplish that goal.
One thing that comes to mind is creating your own Forms/WPF timer at construction time and then use this and some synchronization to hide the details of coordination across threads. We can infer from your sample that construction of your poller should always happen in context of your consumer's thread.
This is a rather hack-ish way to accomplish what you want, but it can accomplish the deed because the construction of your poll-listener happens from the consumer's thread (which has a windows message pump to fuel the dispatches of Forms/WPF timers), and the rest of the operation of the class could occur from any thread as the forms Timer's tick will heartbeat from the original thread. As other comments and answers have noted, it would be best to reassess and fix the operating relationship between your polling operations and the consumer.
Here is an updated version of the class, PollingListener2 that uses a ManualResetEvent and a concealed System.Windows.Forms.Timer to ferry the polling notice across threads. Cleanup code is omitted for the sake of brevity. Requiring the use of IDisposable for explicit cleanup would be recommended in a production version of this class.
ManualResetEvent # MSDN
public class PollingListener2
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
public event EventHandler<EventArgs> Polled;
System.Windows.Forms.Timer formsTimer;
public System.Threading.ManualResetEvent pollNotice;
public PollingListener2()
{
pollNotice = new System.Threading.ManualResetEvent(false);
formsTimer = new System.Windows.Forms.Timer();
formsTimer.Interval = 100;
formsTimer.Tick += new EventHandler(formsTimer_Tick);
formsTimer.Start();
timer.Elapsed += new System.Timers.ElapsedEventHandler(PollNow);
timer.Start();
}
void formsTimer_Tick(object sender, EventArgs e)
{
if (pollNotice.WaitOne(0))
{
pollNotice.Reset();
var temp = Polled;
if (temp != null)
{
Polled(this, new EventArgs());
}
}
}
void PollNow(object sender, EventArgs e)
{
pollNotice.Set();
}
}
This has some precedent in the distant Win32 past where some people would use hidden windows and the like to maintain one foot in the other thread without requiring the consumer to make any significant changes to their code (sometimes no changes are necessary).
Original:
You could add a member variable on your helper class of type Control or Form and use that as the scope for a BeginInvoke() / Invoke() call on your event dispatch.
Here's a copy of your sample class, modified to behave in this manner.
public class PollingListener
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
public event EventHandler<EventArgs> Polled;
public PollingListener(System.Windows.Forms.Control consumer)
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(PollNow);
timer.Start();
consumerContext = consumer;
}
System.Windows.Forms.Control consumerContext;
void PollNow(object sender, EventArgs e)
{
var temp = Polled;
if ((temp != null) && (null != consumerContext))
{
consumerContext.BeginInvoke(new Action(() =>
{
Polled(this, new EventArgs());
}));
}
}
}
Here's a sample that shows this in action. Run this in debug mode and look at your output to verify that it is working as expected.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
listener = new PollingListener(this);
}
PollingListener listener;
private void Form1_Load(object sender, EventArgs e)
{
listener.Polled += new EventHandler<EventArgs>(listener_Poll);
}
void listener_Poll(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("ding.");
}
}
If the processing work inside your PollNow is fairly small then you do not need to perform it on a separate thread. If WinForms use Timer, in WPF you use DispatchTimer and then you are performing the test on the same thread as the UI and there is no cross-thread issue.
This SO question prompted this comment:
I think this excerpt is enlightening: "Unlike the
System.Windows.Forms.Timer, the System.Timers.Timer class will, by
default, call your timer event handler on a worker thread obtained
from the common language runtime (CLR) thread pool. [...] The
System.Timers.Timer class provides an easy way to deal with this
dilemma—it exposes a public SynchronizingObject property. Setting this
property to an instance of a Windows Form (or a control on a Windows
Form) will ensure that the code in your Elapsed event handler runs on
the same thread on which the SynchronizingObject was instantiated."
And System.Times.Timer doc says of SynchronizingObject:
Gets or sets the object used to marshal event-handler calls that are
issued when an interval has elapsed.
Both of which implie that if you pass a control created on the UI thread as the sync object then the timer will effectively marshal the timer event calls to the UI thread.

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