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

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

Answers


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.


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


Need Your Help

unable to run command prompt using java

java windows

I'm just trying to open a command prompt window using java program (in eclipse). When i run pgm as below, it's not showing any message

How to turn off Xcode 6 autoindent text files

xcode xcode6

I use a text file (History.txt) for notes and to keep track of my edits. Xcode 6 is applying the indentation rules to all files, and so manual formatting (using tabs) in my text file is changed wh...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.