BackgroundWorker and Timer, handling one item at a time - c#

My app monitors a directory where users can upload a file. When a new file is detected it is added to a queue. I have a timer that runs through the queue and determines if the file has finished uploading. If there are any files that are complete it will take the most recent and begin running a background task (using BackgroundWorker).
My problem is that I don't know how to handle the timer while the background task is running. For example, if the timer is set to 10 seconds and the background worker is still working I want the timer to skip execution of another background worker until its next iteration.
Also, the information for each task is stored in the Queue (a ListView control) and I pass the ListViewItem to the background worker. I'm curious if passing the ListViewItem has any side effects.
Thanks!

You could store ready-to-process files in another queue (like a Queue< string> ) and have the BgWorker continuously poll that Queue. You might get better performance too, less idle time. You will have to protect the Queue (with Monitor) and have the BgWorker use Monitor.Wait when the Queue is empty.
To get an idea, look for Marc Gravell's answer on this question.

Really hard to answer this without seeing the code you are talking about. However, if you have to synchronize multiple asynchronous events (detecting a file is downloaded, adding the file to a queue, processing the queue) I suggest creating a single BackgroundWorker that does all tasks. Then it is easy in your worker to test what state each step is at. I would avoid creating multiple threads and attempting to synchronize them, this is very very problematic.
I would also not store any background task information in a UI data structure (like a ListView control). Create a callback or event in your BackgroundWorker that will alert the UI when it needs to display something.

Is the BackgroundWorker.IsBusy Property what you're looking for?

The simplest thing you could do is do all the work (including checking the folder) inside your BackgroundWorker: Check if you have something to do, if yes, do it, if not, use Sleep(time) or WaitOne(time) to suspend the thread for some time.
I don't think you need a thread-safe queue here, because folder is being updated asynchronously anyway. So you only need one thread, but you need a way to stop it. That is why AutoResetEvent.WaitOne(time) would be better than Sleep(time) - you can signal the event from the main thread to end your background worker earlier.

On your Timer.Tick handler, check the BackgroundWorker.IsBusy property to determine if it's ready for another bit of work or not. If not, just skip giving it the work and wait until the next Tick.

You can create a thread queue in which you place work-to-do. Your background worker loops around pulling off items from the queue and perform the work.
Some things need to be considered:
The queue needs to be thread safe, and quite likely you'd want the backgroundworker to block if the queue is empty, and wake up when an item becomes available. Im sure somone has made such a nice queue already.
The items you post to the queue will be operated on in another thread(the backgroundworker). Make sure this is done in a thread safe manner (e.g. don't post items to the queue that both the main application and the background worker will alter)
Another and easier approach is to
Queue up items in your application. Kick off the backgroundworker one first time.
When you get the event that the backgroundworker is done, pick the next item off the queue and start the backgroundworker again with this item.
You still need to care about thread safety. When you've sent an item to the backgroundworker, make sure only the backgroundworker operates on it(e.g. if you're just sending it strings, send it a copy of said string instead)
I didn't quite follow you on the timer. If the background worker is finished you should get an event and you'll know it's finished, no need for a timer to check this.

Related

Waiting for event to fire on a main thread from a background thread spawned by it

I have a situation where I am processing some data in a thread that is fired from an event initially, but it needs to wait until something happens in the main thread before continuing - the issue being there could be any number of these running concurrently. The real basic example:
Event Triggered -> Method set to run in the background on its own thread -> send data using the main thread's send data method -> Wait for an ACK for receipt of that data -> Set the WaitHandle on the main thread -> worker thread will then send the next set of data -> repeat -> exit thread when all data has been sent and ACK'd.
Currently I have one AutoResetEvent that is set each time an ACK comes in - and the worker thread that is running will listen for that - but if there happens to be 10 of those worker threads running at once, and they are all listening to it - it defeats the purpose.
I need to spawn the worker thread, and have it listen (WaitOne) for a specific WaitHandle to be set/reset, and continue based on that only.
What would be the best method for accomplishing something like this? Somehow create an array of WaitHandles and have the worker thread listen for the AutoResetEvent of its index?
I'm not sure on the exact way that your threads and your other process are interacting but a pattern I've used before is a dictionary, where a manual or auto reset event is the value, and you set some kind of ID as the key e.g the event, event sender, user ID whatever.
That way you can search for the relevant ID in the dictionary (using the default indexer) and then wait on the handle. If you need to add wait handles to the list asynchronously (e.g. as the events are raised) you may need to use a ConcurrentDictionary class. I'm not exactly sure what you need, but you could also look at a queue if you need to wait on all events being complete before completing some action.
Watch out for cross thread synchronisation. You don't want to block your main thread on a GUI app, and you can't edit a GUI from the same thread
I think you're digging a little too low-level in your abstractions. Is there a reason you can't use a much more typical producer-consumer model with a queue or two to handle in-flight requests and responses? It's going to be a lot easier to get it correct when you're not trying to recreate low-level synchronization primitives.

BackgroundWorker might be causing my application to hang

I have a Form that uses a BackgroundWorker to execute a series of tests. I use the ProgressChanged event to send messages to the main thread, which then does all of the updates on the UI. I've combed through my code to make sure I'm not doing anything to the UI in the background worker. There are no while loops in my code and the BackgroundWorker has a finite execution time (measured in seconds or minutes). However, for some reason when I lock my computer, often times the application will be hung when I log back in. The thing is, the BackgroundWorker isn't even running when this happens. The reason I believe it is related to the BackgroundWorker though is because the form only hangs when the BackgroundWorker has been executed since the application was loaded (it only runs when given a certain user input).
I pass this thread a List of TreeNodes from a TreeView in my UI through the RunWorkerAsync method, but I only read those nodes in the worker thread..any modifications I make to them is done in the UI thread through the progressChanged event.
I do use Thread.Sleep in my worker thread to execute tests at timed intervals (which involves sending messages over a TCP socket, which was not created in the worker thread).
I am completely perplexed as to why my application might be hanging. I'm sure I'm doing something 'illegal' somewhere, I just don't know what.
I pass this thread a List of TreeNodes from a TreeView in my UI through the RunWorkerAsync method, but I only read those nodes in the worker thread.
By "only read" I assume you mean "only access property getters". But property getters can execute code that you don't control - for example TreeNode.IsSelected will call a native method and send a Windows message (take a look with Reflector).
Instead you should extract the data you need from the TreeView in the UI thread and pass it to the background worker. Not only will you avoid this problem, but your design will be more loosely coupled.
Well, this one is old but it turned out that the problem was completely unrelated to my code. Due to recent changes in our software, the amount of logging had increased exponentially and our log buffer was overflowing causes the application to crash. It was just a coincidence that this was happening at the same time that I was working on this specific piece of code. In any case, I still made sure that I wasn't doing any operations on UI elements from a BackgroundWorker, even if it was as trivial as checking/unchecking a TreeNode.
Sounds like the dreaded UserPreferenceChanged event problem where a ui component has been created on a background thread without a message pump. The main ui thread synchronously sends the event to all registered ui windows and will hang because the ui component on the background worker thread is unable to process the UserPreferenceChanged event.

Performing periodic audits and best practice

I'm doing a windows form and would like an audit task to happen every 30 seconds. This audit is essentially checking a series of services on remote computers and reporting back into a richtextbox the status.
Current I have this running in an endless background thread and using an invoker to update the richtextbox in the main form.
Is this best practice? If I made an endless loop in my main form that would prevent any of my buttons from working, correct?
I'm just curious if every time I want to create a periodic audit check I have to create a new thread which checks the status or file or what have you?
Edit: I looked further into the Timer class and decided to go with System Timer as it proved to be better with a longer function. Thanks for pointing me in the right direction.
You should look into the Windows Forms Timer class. You don't want a loop in your main form. It's better to use the timer to fire events which can be processed asynchronously on another thread.
(I assume this is a winform application)
Invoking on the main thread is the way to go. But what about using a timer instead of an endless loop? It gives you more control. And a the timer function would execute on it's own thread.
It's good practice to let long going work execute on a background thread, so that the main thread can work with the UI.

How do I reduce interface lag in C#?

I have a problem with interface lag in C#.
Since I'm still learning please be patient whilst I explain.
I have narrowed the problem to my timer object.
Basically my program queries a device through TCP/IP socket and outputs it to a textbox on screen.
Now I am polling the device for data every second which requires some logic to be buried within timer object and the following is what happens between ticks:
Increment a value.
Construct the 2 strings that represents the command to be sent to
the box (encapsulated in a function
Encode the command
Send command
Clear the byte array
Receive reply.
Could this be too much processing being done in the event handler? Every time I try to move the window during the polling session i.e. when the timer is running I get a very bad input lag.
The timer you are using is executing on the windows message thread. Therefore, while the polling is running the windows message queue is blocked. This isn't a problem with doing too much processing, most of the time the thread will be waiting for the TCP/IP response.
To fix this, you just have to do the do the work on a background thread and then update the UI on the UI thread.
There are a heap of different timers in the .NET framework that work in different ways, the one you are using works processed the timer event on the same thread, others work on background threads. Check this article out about the different timers.
You could also just use your current timer to invoke a BackgroundWorker component to do the work on the background thread. The main benefit of this is the the BackgroundWorker will do the work on a background thread, but will raise the work complete event on the UI thread so that it is simple to update the UI without having to worry about which thread you are on.
I think this is because you're trying to do work in your UI thread. Have your timer run in a background work thread.
It seems like there are a few things going on. First, you may be doing too much in your timer tick handler. How are you constructing the string and encoding the command? Can any of this be done once outside the tick handler or simplified in any way (using String.Format calls, for instance)? There are actually three different timers available in .NET, with different resolutions. Which timer are you using?
The biggest issue is the fact that your interval is 1 second. No matter what, that is a lot of processing overhead. Keep in mind that, for the most part, every time the interval is hit and the tick handler is invoked you are causing a context switch between threads. There is a bit of overhead involved in this (nothing which you can do anything about) and the more often you context switch the slower your performance appears.

Winforms should I multi thread or use event timer?

I currently have a thread that listens for data from the network and then runs rules on it. I then want to pass the data to the GUI. I am worried about having a deadlock in the GUI. I cant figure out were to put the mutexes on the GUI side. I am also using c# and dotnet 3.5.
What I have come up with is
1) Using a timer to create an event and dump the thread. Worried about performance.
2) Use an intermediary event to copy the data to GUI.
3) Dig in and figure out thread safe way of using GUI.
What do you think is best way to proceed?
Edit: Here is the solution I am using. I pass in the changed element and then protect the big object with a mutex. I use helper function to switch threads using InvokeRequired then BeginInvoke with a delegate. Pulled from reading the answers and then following links until reaching Threading in Windows Forms by Jon Skeet.
delegate void UInt32ParameterDelegate(UInt32 n);
public void UpdateLocation(UInt32 n)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new UInt32ParameterDelegate(UpdateLocation), new object[] { n });
return;
}
// Must be on the UI thread if we've got this far
this.engine.location.UpdateBusy.WaitOne();
// do the work in here
this.engine.location.UpdateBusy.ReleaseMutex();
}
Synchronization is very easy in Windows Forms. You can call Control.Invoke() in the background thread. The thread will stall until the delegate has finished running on the UI thread. No sync required at all.
If stalling the thread is a problem, use Control.BeginInvoke(). You'll have to protect the object(s) you pass to the delegate with a lock if the thread might alter them while it continues running. That's rarely the case in a producer-consumer scenario, the thread can simply create new objects.
Do make sure that you don't Invoke() too often. Do it more frequently than about 1000 times per second and the UI thread will stop pumping Windows messages, being bogged down by handling the invoke requests. Since it is human eyes you're trying to please, invoking more than about 25 times per second is just wasted effort. Pool intermediate results in a collection object.
I hope I understand your problem correctly.
After the background thread reads the data and does whatever it wants, it should use Invoke to call a method on the GUI thread. That method would update anything that should be updated in the GUI.
Never read from the network on the GUI thread. It's only a matter of time before your application runs during a network outage and your GUI hangs as a result. This will really frustrate your users.
In your situation I think the best approach is to have a background thread complete the read operation. Then take the resulting data and move it back to the GUI thread via a SynchronizationContext Post or Send method.
you should just pass an event from your network thread to your UI thread.
then cross threads using begininvoke so you don't get a cross thread exception.
Need help getting info across a UI thread and another thread in C#
You could use a backgroundworker that will process the datareading in a background thread and when it's done you can end the backgroundworker triggering it's RunWorkerCompletedEventHandler. In the RunWorkerCompletedEventHandler you can update your GUI thread with the result.
Isn't easier to just throw a delegate who raise an event that inform the form to refresh itself?

Categories