C# - Can Threads behave like BackgroundWorkers (winForms)? - c#

I'm trying to work with Threadding and it seems to me like it's suspiciously difficult (I'm probably doing it wrong).
I want to load a file inside a BackgroundWorker and while that happens, "send" each new line to a separate Thread (not bgWorker). I'm using BlockingCollection and Add() each line, then I want to Take() them and process them in another thread.
Now, everything is straightforward with the BgWorker; but why is it impossible(isn't it?) to just declare a new thread in Form1.cs and have it perform like the BgWorker? In other words, why must you create a separate WorkerClass ( http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx )?
I'm asking this because, you can access your BlockingCollection fine from within the BackgroundWorker, but you can't do it from a separate WorkerClass (since it's a plain vanilla separate class). (So what's the point of the BlockingCollection then if you can't use it for what it's meant?)
Also, BgWorkers have a ReportProgress(...) event/method. As far as I know, if you use that msdn example, you don't have squat in your Thread.
What am I missing here? Please help.
PS: Before you jump and tell me that It's not in any way more efficient to send lines to another thread, know that I'm doing this as a learning exercise. Trying to figure out how Threads work in C# and how you sync/communicate between/with them (and/or bgWorkers).

Answering specifically why working with threads is more difficult than working with a background worker....
The backgroundworker is actually a method for creating another thread wrapped up in an easier to use package. The reason working with threads directly is harder is because it's closer to the real thing.
For a similar comparison, using System.Net.Mail to send an email is just a simplified way of creating socket connections, etc... Under the hood, the System.Net.Mail classes do the detailed work. Similarly, under the hood, the BackgroundWorker does the detailed work of dealing with the threads.
As a matter of fact, the MSDN documentaiton for the backgroundWorker object starts out like this:
BackgroundWorker Class Updated:
September 2010
Executes an operation on a separate
thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
So if the backgroundworker class is supposed to make threading easier, why would people want to work with threads directly? Because of the issue you're having. Sometimes the "friendly wrapper" leads to a loss of fine control.
Edit - added
What you're asking about in the comments is thread synchronization. This article covers it pretty well.
http://msdn.microsoft.com/en-us/magazine/cc164037.aspx
and this article answers "communicating between threads" explicitly.
http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic63233.aspx

To answer your question in the title, yes "normal" threads can act like BackgroundWorker threads. You just have to create more of the wiring code yourself.
I wrote a simple application for scanning my music collection using a manually created thread. The main body of the thread is a method that loops over all of the folders under a specified root and fires an event each time it encounters a folder that contains some mp3 files.
I subscribe to this event in the main form of my application and update a DataGridView with the new information.
So the thread is kicked off by the following code:
this.libraryThread = new Thread(new ThreadStart(this.library.Build)) { IsBackground = true };
// Disable all the buttons except for Stop which is enabled
this.EnableButtons(false);
// Find all the albums
this.libraryThread.Start();
The method supplied to ThreadStart does some housekeeping and then calls the method that does the work:
private void FindAlbums(string root)
{
// Find all the albums
string[] folders = Directory.GetDirectories(root);
foreach (string folder in folders)
{
if (this.Stop)
{
break;
}
string[] files = Directory.GetFiles(folder, "*.mp3");
if (files.Length > 0)
{
// Add to library - use first file as being representative of the whole album
var info = new AlbumInfo(files[0]);
this.musicLibrary.Add(info);
if (this.Library_AlbumAdded != null)
{
this.Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
}
}
this.FindAlbums(folder);
}
}
When this method finishes a final LibraryFinished event is fired.
I subscribe to these events in the main form:
this.library.Library_AlbumAdded += this.Library_AlbumAdded;
this.library.Library_Finished += this.Library_Finished;
and in these methods add the new album to the grid:
private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
{
this.dataGridView.InvokeIfRequired(() => this.AddToGrid(e.AlbumInfo));
}
and finish off (which reenables buttons etc.):
private void Library_Finished(object sender, EventArgs e)
{
this.dataGridView.InvokeIfRequired(() => this.FinalUpdate());
}
As you can see this is a lot of work which would be a whole lot simpler if I used a BackgroundWorker.

Related

visual studio drawing adornment with lazy update

I'm making an Visual Studio adornment extension. I want to update adornments if there is no user input at least 2 seconds. So i constructed a worker and tried to remove and add adornment but VS says it can't be updated because non-ui thread had called it. So I waited without thread then my editor goes really laggy (because the ui thread waits)
I want to know if there is a way to update adornments with lazy update.
Drawing adornment is done by calling AddAdornment(), and i can't find how to invoke ui thread to draw.
Below is my code
internal async void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
Print("OnLayoutChanged Called");
task = Task.Factory.StartNew(() =>
{
Print("task Started");
if (e.NewSnapshot != e.OldSnapshot)
{
parseStopwatch.Restart();
shouldParse = true;
}
ParseWork(e);
});
await task;
}
private async void ParseWork(object param)
{
var e = (TextViewLayoutChangedEventArgs)param;
if (e == null)
{
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRegionBox();
return;
}
while (shouldParse)
{
Task.Delay(10);
if ((shouldParse && parseStopwatch.ElapsedMilliseconds > 2000) || parseStopwatch.ElapsedMilliseconds > 5000)
{
break;
}
}
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRequest(e);
return;
}
I'm not sure why you were down-voted, particularly because this is an interesting problem when dealing with extensions.
So, to your first problem: Visual Studio has the same requirements as WPF (with some added complications due to its COM dependency). You can't update a UI element when you're not on the Main (UI) thread. Unfortunately, if you dive right in and approach it using the strategies you'd use for WPF, you'll experience a whole other world of problems (deadlocks, mostly).
First things first, brush up on how to handle switching from background to UI threads in Visual Studio extension land. I found Asynchronous and Multithreaded programming within VS using JoinableTaskFactory to be helpful in explaining.
I had to do something similar with an expensive parsing operation. It was pretty straight forward.
My parser executes as part of an IViewModelTagger instance and uses the following sequence (roughly):
It subscribes to the ITextBuffer.ChangedLowPriority event with an async void event handler.
Immediately on fire, it cancels any parsing operation in progress via a CancellationToken.Cancel() call. The cancellation token is passed into everything that supports it (in Roslyn, it's supported everywhere you would want it to be).
It begins the parsing operation, but before starting it, I have a Task.Delay(200, m_cancellationToken) call. I 200ms based on my typing speed and the fact that Roslyn's operations have CancellationToken overloads for anything expensive (my parsing work is pretty light-weight, too). YMMV.
I work with WPF components that require the UI thread quite a bit and they're intermingled within the IViewModelTagger and the IWpfTextViewListener. They're lightweight enough that I could have skipped async'ing them, but on very large classes they can hang the UI.
To handle this, I did the following:
On the TextViewLayoutChanged, I subscribe with an async void event handler.
I Task.Run() the expensive operations first, preventing the UI from being blocked.
When I do the final creation of the WPF UI elements and add them as adornments finalization (along with a couple of operations within the SDK that require it), I await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync() to get the UI thread.
I mentioned "other SDK operations", that's important. There are several things you cannot do within the SDK on anything but the Main thread (memory is failing me now, but parts of the TextView in particular will fail, and not consistently, if they're accessed on background threads).
There are more options for executing the work off of the UI thread (Ordinary Task.Run works, as well as ThreadHelper.JoinableTaskFactory.Run). The Andrew Arnott post linked earlier in my answer explains all of the choices. You'll want to understand that fully since there are reasons to use some over others depending on the task.
Hope that helps!
Task.Delay as used in your code returns a task that completes when you delay. If you call it like that and ignore the result, it didn't do what you thought it did. What you probably meant to is instead of calling Task.Factory.StartNew as you did, you want:
var cancellationTokenSource = new CancellationTokenSource();
Task.Delay(2000, cancellationTokenSource.Token).ContinueWith(() => DoWork(), cancellationTokenSource.Token, TaskScheduler.Current).
This says effectively "kick off a timer that'll wait 2 seconds, and then once it completes run the DoWork method on the UI thread. If more typing happens, then you can call cancellationTokenSource.Cancel() and just run again.
Also, I do have to ask about your type "CSharpRegionParser". If you need region information and you're on Visual Studio 2015, then you can get the syntax tree from Roslyn and you should be watching workspace change events rather than hooking LayoutChanged. You're also best off then structuring your system as a tagger/adornment manager pair as it might be clearer to write...it's not clear to me why you'd do parsing logic in LayoutChanged since LayoutChanged is something that happens during visual layout, including scrolling, resizing, etc.

Custom Events and Threading

I have two different projects and in one, I have a class that defines a custom event to fire under certain conditions:
public delegate void ButtonHandler(object myObject,
GuitarArgs myargs);
public event ButtonHandler OnButtonPress;
... other stuff ...
GuitarArgs myArgs = new GuitarArgs( guitarState );
if(OnButtonPress!= null)
OnButtonPress(this, myArgs);
Then in another project I create an instance of this class and subscribe to this event:
Guitar.OnButtonPress += Guitar_OnButtonPress;
The event then fires properly, but it seems to be on a different thread, because when I try to access some UI elements, I get an error : The calling thread cannot access this object because a different thread owns it.
The code throwing the error is:
void Guitar_OnButtonPress(object myObject, Guitar.GuitarArgs myargs)
{
GuitarCheck(myargs.State);
}
private void GuitarCheck(GuitarState getState)
{
if (getState.green)
{
VisualTreeHelper.HitTest(guitarCanvas, null,
MyHitTestResult,
new GeometryHitTestParameters(
new RectangleGeometry(new Rect(1, 411, 88, 78))));
}
}
What can I do to make this run?
Thank you.
You need to check if your event handler is running on a non-UI thread and, if so, invoke it on the UI thread:
How to update the GUI from another thread in C#?
I would like to highlight the less-upvoted answer, which provides a very elegant approach using an extension method. I use this in all of my WinForms projects (and use a variant in WPF/Silverlight projects)
https://stackoverflow.com/a/3588137/141172
If you are using WinForms
this.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx)
If you are using WPF
this.Dispatcher.Invoke(() => GuitarCheck(myargs.State));
(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx)
So you have an event called OnButtonPress whos event handler is obviously executing on a thread that is not hosting VisualTreeHelper. The big question for me is...why? With a name like OnButtonPress it makes me think it should already be on the UI thread. Afterall, it is a button press right? So why is it executing on another thread to begin with?
Using a marshaling operation like Invoke or BeginInvoke is fine as long as you are aware of why it is needed and what it accomplishes for you. But, you really need to take a step back and identify what all is going on that would cause you to need to use a marshaling operation in the first place. There may be a bigger issue here that you need to address.

Need explanation on event handling and delegates

I have some code that I wrote, which does what I want. However, I am not quite sure how, exactly, it works. The part I am having the most trouble with is the last part. I had a textBox1.Text = "test" which did not work. I got a run time error about it being called from a different thread. When I put the textBox1.Invoke(etc etc), it worked as expected. Why?
As you can see, I know just enough to be dangerous and I really want to understand what's going on here instead of blindly copying and pasting from sites around the web.
I have the following in a class named SerialCommunicator:
public SerialCommunicator(SerialPort sp)
{
this.sp = sp;
sp.ReceivedBytesThreshold = packetSize;
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
}
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
SerialPort s = (SerialPort)sender;
byte[] buffer = new byte[128];
s.Read(buffer, 0, s.BytesToRead);
}
Then, in my Form1.cs I have a button that when pressed does the following:
private void btnPortOK_Click(object sender, EventArgs e)
{
string comPort = cboComPorts.SelectedItem.ToString();
SerialPort sp = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
sp.DataReceived += new SerialDataReceivedEventHandler(DataHasBeenReceived);
comm = new SerialCommunicator(sp);
}
public void DataHasBeenReceived(object sender, EventArgs args)
{
textBox1.Invoke(new EventHandler(delegate { textBox1.Text += "test"; }));
}
This is thread-affinity. UI controls don't like to be touched by anything except the thread that created them, but the DataReceived thread happens from a different thread. Adding a call toControl.Invoke pushes an item of work back to the UI thread, so the Text updated can succeed.
I am not an expert on this (there will likely be better answers than this). But as I understand it, the GUI thread "owns" your form. So when you try to update it from a different thread you are crossing the streams.
The Invoke is a way to ask the GUI thread to run a method. Method that it runs is your textBox1.Text += "test";
The idea is by invoking a delegate, that will ask the GUI thread to make the change, rather than just changing the value yourself. This allows allow the change to be done in a thread safe manner.
Here is a good article by Jon Skeet on this issue:
http://www.yoda.arachsys.com/csharp/threads/winforms.shtml
Events are called from the thread where they happen. (Unless specified otherwise).
Think about this way:
When you activate the event, it is actually called as a finction EventName(). So calling an event means actually going to all the methods that were registered to that event and doing them.
But, this is done in the same thread in a serial way.
So if an event happened in a thread that is not your UI thread you'll get theat error.
The issue is that the GUI components only accepts modifications from the GUI thread. So when other threads want to modify the GUI, then they must queue their modification code using measures like control.Invoke(...) which will queue the delegate to be processed as soon as possible on the GUI event queue, and thus the correct thread.
What you run in to is that one of the built-in checks are fired than controls that the calling thread indeed is the correct thread. It is a security measure that makes debugging easier (if they were not present you would have to debug subtle threading issues instead...)
textBox1.Text = "test" doesn't work because you are calling it from another thread (i.e. the DataHasBeenReceived event) then the thread who owns the textbox. That's usually the thread in which your application runs and that creates your GUI interface (and thus your textbox). Invoke works because that methods switches to the GUI thread, sets your text and then switches back to the thread of your DataHasBeenReceived event.
In Net 1.0 and 1.1 you could use GUI controls from another thread then then the one that owned them but this resulted in a lot of problems when threads started accessing the controls at the same time. So, since net 2.0 Microsoft changed that.
If you want to know if must use invoke or not (i.e. if a method can be called from the both the GUI thread or another thread), you can use the property InvokeRequired combined with an if else. A invoke call is slightly more expensive then a direct manipulation of the control.

Is BackgroundWorker the only way to keep a WCF/WPF application responsive?

Client/server desktop application using C#, WCF, WPF. Since pretty much every action is going to require a trip to the server (list/create/save/delete/etc), every action has the potential to freeze the entire UI. Here's an example of a naive implementation with a call to service.GetAll() which could take a "long" time (more than a few hundred milliseconds):
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
vm.Users.Clear();
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}
(Aside: I'd love to know why List has AddRange and ObservableCollection doesn't.)
BackgroundWorker to the rescue:
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
e.Result = service.GetAllUsers();
};
worker.RunWorkerCompleted += (s, e) =>
{
vm.Users.Clear();
foreach (var user in (List<UserDto>)e.Result)
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
};
worker.RunWorkerAsync();
}
(Aside: code above has been simplified, but that's the gist of it.)
The code using BackgroundWorker works exactly how I want it to. The app remains responsive at all times, and the button is disabled for the duration of the call. However, this means adding 15 lines to every possible action the user might make.
Say it ain't so.
No, BackgroundWorker is not the only way, but it's one way. Any other way will allso include some form of asynchronous construct with the need to use Dispatch.BeginInvoke to update the UI. You could for instance use the ThreadPool:
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
});
If this is a recurring pattern (a button will trigger some action that should be performed asynchronously, with the button being disabled during the process) you can wrap this into a method:
private void PerformAsync(Action action, Control triggeringControl)
{
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = false; });
action();
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = true; });
});
}
...and call it:
PerformAsync(() =>
{
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}, btnRefresh);
As an option to using the ThreadPool, you should also perhaps look into the Task Parallel Library.
When doing this you should pay attention to how you handle UI state. For instance of you have more than one control which triggers the same action, make sure that all of them are disabled during the action.
Note: these are just quick ideas. The code has not been tested so it may contain errors. It's more to be regarded as discussion material than finished solutions.
WCF provides the ability to make all service calls asynchronously. When you create the service reference in your project, the add service reference dialog box has an "Advanced..." button. Clicking that you will see the option for "Generate Asynchronous operations". If you click that check-box then every operation will be generated in both a synchronous and asynchronous manner.
For example, if i have an operation "DoSomething()" then after checking this box i will get code generated for calling DoSomething() and DoSomethingAsync().
You will also get a Service.DoSomethingCompleted event that you can use to define a callback handler when the service call returns.
This is the method we used to make service calls without locking the UI.
Here is a rather complicated example provided by Microsoft on how to do this: http://msdn.microsoft.com/en-us/library/ms730059.aspx
It is not the only way. I recommend Task (or one of the higher-level abstractions for Task, such as Parallel or PLINQ).
I have a review of various approaches to asynchronous background operations on my blog.
The current state of things does require some boilerplate code, regardless of which approach you choose. The async CTP shows where things are going - towards a much, much cleaner syntax for asynchronous operations. (Note that - at the time of writing - the async CTP is incompatible with VS SP1).
Well, BackgroundWorker is not the only option you have but in order to accomplish what you want you still need to use multiple threads or asynchronous operations in order to not block while you wait for the long-running operations to finish.
And, because WPF requires that all code accessing the UI run on the same thread you do have to do some context switching when you call or access data or code on the UI thread. The way to ensure a call will run on the UI thread in WPF is to use the Dispatcher class.
Another simple way of keeping the UI responsive is to queue work item on a thread in the Thread Pool which is done using the ThreadPool class.
// assuming the the following code resides in a WPF control
// hence "this" is a reference to a WPF control which has a Dispatcher
System.Threading.ThreadPool.QueueUserWorkItem((WaitCallback)delegate{
// put long-running code here
// get the result
// now use the Dispatcher to invoke code back on the UI thread
this.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)delegate(){
// this code would be scheduled to run on the UI
});
});
As always, there's more than one way to skin the cat but be aware that each technique has advantages and disadvantages. For instance the method outlines above could be useful because it doesn't have that much code overhead but it may not be the most efficient way in may cases.
Other options are available including using the BeginXXX - EndXXX methods of the classes you're using if they provide any (such as the SqlCommand class has BeginExecuteReader EndExecuteReader). Or, using the XXXAsync methods if the classes have that. For instance the System.Net.Sokets.Socket class has ReceiveAsync and SendAsync.
No this is not the only option. This question is more about how are you designing your application.
You can take a look at Windows Composite Applicaiton Framework (Prism), which provides features like EventAggregator which can help you publish application wide events out and subscribe it at multiple locations within your app and take actions based on that.
Also as far as being worried about having too many lines of code, you may want to layer your application architecture in such a way that you can refactor and reuse as much code as possible. This way you have these background workers handling all your service responses in one layer while you can leave your UI layer detached from it.
No it's not the only way, but it is one of the simpler ones (at least compared to setting up your own thread, or pushing a task to a thread pool thread and arranging an event on completion).
You might be able to simplify a little bit by writing a static method somewhere that takes two parameters, the callback functions, and handles the rest for you, that way you won't have to write all the same boiler plate every time you need to make an async call.
No, certaily not.
You can create a raw Thread and execute time taking code in it and then dispatch the code to the UI Thread to access/update any UI controls.More info on Disptacher here.
Refer to this for a great information about Threads in c#.

Waiting for either of these BackgroundWorker to complete

There is a sequence for FORM(some UI) should get downloaded using service.
Currently, this download is in a BackgroundWorker Thread.
Now, since the performance is slow... We decided to categories the FORMS into 2 and start downloading parallely using another BackgroundWorker on top of the existing Thread.
Now, the scenario is the either of this BackgroundWorker should wait for other to complete.
So, how to implement it.
I tried with AutoResetEvent. but, i could not achieve this.
Any help is appreciated.
I don't think that the scenario is really that one BackgroundWorker should wait for another. What you really want is to fire some UI event after (and only after) both of them complete. It's a subtle but important difference; the second version is a lot easier to code.
public class Form1 : Form
{
private object download1Result;
private object download2Result;
private void BeginDownload()
{
// Next two lines are only necessary if this is called multiple times
download1Result = null;
download2Result = null;
bwDownload1.RunWorkerAsync();
bwDownload2.RunWorkerAsync();
}
private void bwDownload1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download1Result = e.Result;
if (download2Result != null)
DisplayResults();
}
private void bwDownload2_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
download2Result = e.Result;
if (download1Result != null)
DisplayResults();
}
private void DisplayResults()
{
// Do something with download1Result and download2Result
}
}
Note that those object references should be strongly-typed, I just used object because I don't know what you're downloading.
This is really all you need; the RunWorkerCompleted event runs in the foreground thread so you actually don't need to worry about synchronization or race conditions in there. No need for lock statements, AutoResetEvent, etc. Just use two member variables to hold the results, or two boolean flags if the result of either can actually be null.
You should be able to use two AutoResetEvent's and the WaitAll function to wait for both to complete. Call the Set function on the AutoResetEvent objects in the respective OnRunWorkerCompleted event.
Jeffrey Richter is THE guru when it comes to multi threading and he's written an amazing library called Power Threading Library which makes doing tasks like downloading n files asynchronously and continuing after they are all completed (or one or some), really simple.
Take a little time out to watch the video, learn about it and you won't regret it. Using the power threading library (which is free and has a Silverlight and Compact Framework version also) also makes your code easier to read, which is a big advantage when doing any async stuff.
Good luck,
Mark
int completedCount = 0;
void threadProc1() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
void threadProc2() { //your thread1 proc
//do something
....
completedCount++;
while (completedCount < 2) Thread.Sleep(10);
//now both threads are done
}
Just use 2 BackgroundWorker objects, and have each one alert the UI when it completes. That way you can display a spinner, progress bar, whatever on the UI and update it as download results come back from the threads. You will also avoid any risks of thread deadlocking, etc.
By the way, just so we are all clear, you should NEVER call a blocking function such as WaitAll from the UI thread. It will cause the UI to completely lock up which will make you users wonder WTF is going on :)

Categories