2

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).

4
  • If you want to learn how threads work then don't use BGW, it will keep you out of trouble too much. Commented Dec 3, 2010 at 20:05
  • 1
    If you use BlockingCollection then you're on Fx4 and you should look into Tasks (TPL) rather than threads. Commented Dec 3, 2010 at 20:49
  • @Henk; Dude. Thanks. (I'm still going to look into threads but) Thank you for telling me about the existence of System.Threading.Tasks. Let the record show that this is "what I wanted" (BlockingCollection + Tasks): codethinked.com/post/2010/02/08/… Commented Dec 3, 2010 at 20:59
  • How big is the file you want to send? It has to be many megabytes. Commented Nov 10, 2024 at 12:09

2 Answers 2

3

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

Sign up to request clarification or add additional context in comments.

4 Comments

Well that's just great."The real thing" doesn't seem to me like much of an advantage over the same-thing-only-better-and-miles-easier BgWorker.. Regardless, how do you (can you?) use BlockingCollection on normal Threads?
The issue I'm having is that I'm able to communicate fine between BgWorkers and I can't see any direct/specific way of doing it with regular Threads..
@Twodordan - fire an event with your object as the parameter.
ChrisF, can you elaborate a bit? (I know what events are but how would they help me send stuff cross-thread-wise?)
2

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.

3 Comments

This is a very helpful example. (explains my "how do would events help you" question). I don't understand what this.library.Build is though. Is library a class? or what?
@Twodordan - It's a class I created that represents a media library. The name could be better I suppose. The FindAlbums method resides in that class.
Thank you very much. It all makes sense now :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.