Multithreading in C#

Multithreading is something that seems to keep popping up on me when I am coding. My applications either need to do some crazy calculation (and not return 42) or a function will be waiting for a while before returning anything. Both of these leave my GUI locked up to the point where in Vista I get a straight black screen and the wait O, and in XP if I click on the GUI I get yelled at for touching an application that is not responding. I soon learned you can't just call all your code out of the GUI, there are these sweet abstractions like…Business Logic Layer, and Data Access layer. But that's not what this post is about. If I get my code away from the GUI but it is still called by say, a button click, the process will still not respond and the user will be unable to interact with the GUI or get any feedback about execution.

The answer to this problem is fairly simple Multithreading! There are a few different ways to go about it. The two I've used the most are what I will talk about, BackgroundWorkers and Threads.

System. ComponentModel.BackgroundWorker

BackgroundWorkers were the easiest way for me to get into multithreading an application, and they are the first way I did. BackgroundWorkers take care of all the busy work behind the scenes for you, you don't even have to know what a thread pool is, or Mutex, or Semaphore, or even apartment states. There are some setbacks though. You can't build a Ferrari with legos.

To get your BackgroundWorker going first create a BackgroundWorker object, this takes no arguments. There are a few events you will need to handle as well. DoWork is called when the BackgroundWorker is started from RunWorkerAsync; DoWork is where the meat of your processing intense code will go. If you need to pass an argument to your thread you can use RunWorkerAsync(object), the drawback is you can only send one object to the worker so you may need to write your own container class. ProgressChanged is called when ReportProgress(int) is called, one drawback of this is you can only represent completion on a 1-100 basis (progress bar) which for some applications makes sense but there is no built in method of text feedback on progress. And lastly you will need to handle RunWorkerCompleted which is called whenever the worker ends. This could be because of an error in the thread, the thread dying naturally or by calling CancelAsync.

BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

In bw_DoWork any arguments passed to the worker are in DoWorkEventArgs.Argument but this example takes no arguments.

void bw_DoWork(object sender, DoWorkEventArgs e)
{
 e.Result = doMassiveWorkOMG();
 return
;

}

ProgreessChanged is simple enough. If I have some metric to determine what point in finishing I am at I can update a progress bar to show the user that progress. Inside the doMassiveWorkOMG function:

while(stillDoingEpicWork)
{
 bw.ReportProgress(percentComplete);
}

 

Simple enough right? So now when doMassiveWorkOMG is done with its work bw_RunWorkerCompleted will be called. Inside bw_RunWorkerCompleted we need to handle and errors that may have occurred (if we care) and handle what happens at the end of worker execution.

 

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
 if
(e.Cancelled)
  throw
new OMGWhyDidYouCancelMeException();
 else
if (e.Error != null)
  throw
e;
 else

 {
  sendResultToSomeplaceAwesome(e.Result);
  giveChildrenOfTheWorldCandy();
 }
}

That's all there is to BackgroundWorkers, fairly simple and gets the job done. Now lets do the same thing in a Thread.

System.Threading.Thread

Threads have a bit more going on, and as such are a little more dificult to use but provides more. Creating threads is a little more dificult than a BackgroundWorker; a Thread takes a ThreadStart object or a ParameterizedThreadStart delegate that links to a void(void) or void(object) function respectivly. So to recreate our previous example we would create our thread like this

Thread myThread = new Thread(ThreadStart(doMassiveWorkOMG));
myThread.Name = "MassiveWorkThread";

I should mention, calling "new Thread()" is discouragedthe favored use is calling ThreadPool.QueueWorkItem.

The name only helps us while in the debugger we can see where the thread is running in the Thread Window. There are plenty of other properties to set for the thread such as Priority which sets the priority of the thread, IsBackground which sets wheather the thread runs as a background process or not, and ApartmentState which lets you set if the ApartmentState of the thread is STA or MTA.

Starting the thread is as simple as BackgroundWorker in that we simply need to call myThread.Start() which calls the function we put in our ThreadStart delegate, In this case doMassiveWorkOMG. Keeping track of progress isnt as simple as a BackgroundWorker but in much the same way we increment a progress bar we can update a status label.

public void updateWorkPercentage(int progress)
{//update the progress bar to a new value
 theBestProgressBar.Dispatcher.Invoke(DispatcherPriority.Normal, new System.Windows.Forms.MethodInvoker(delegate()
 {
  theBestProgressBar.Value = progress;
 }));
}

public void updateApplicationStatus(string message)
{//update a status label with a new message
 amazingLabel.Dispatcher.Invoke(DispatcherPriority.Normal, new System.Windows.Forms.MethodInvoker(delegate()
 {
  amazingLabel.Content = message;
 }));
}

It is worthwhile to say this method can be used in a BackgroundWorker as well. Take note that I didn't just call label.content or progressBar.value. Since this will be called on a thread that isnt the GUI thread you will end up with a sweet "The calling thread cannot access this object because a different thread owns it." error if you try to call it dirrectly. For an explination of exactly why it must be done this way look here.

Since we don't have a RunWorkerCompleted function or even the ReportProgress function in threads we have to modify the function we call (doMassiveWorkOMG) to handle updating its status, reporting its results (to the GUI/another function/etc)

void doMassiveWorkOMG()
{
 while
(stillDoingEpicWork)
 {
  updateWorkPercentage(percentComplete);
  updateApplicationStatus(currentStatusMessage);
  epicWorkResult = doMoreEpicWork();
 }
 reportWorkResult(epicWorkResult);
}

There are plenty of ways to get values back from the thread which are easily googleable and Im going to leave out here to keep the post under 90 pages.

 

When should I use what!?

Well, I cant tell you that, you know the scope of your application better than I do. But I tend to use BackgroundWorkers when I just need a simple function running in a thread. If I need the ability to pause/resume, access COM objects like the clipboard I use a Thread with an STA Apartment State (BackgroundWorkers cant do COM Interop that I have found).

In the end you can make a BackgroundWorker do almost anything you can make a Thread do with a little work. But I would rather just use the BackgroundWorker as it is and move to Threads if I need anything more.

Why I’m not buying a 3G iPhone

Since the iPhone 3G was announced at WWDC'08 it seems like it's the new phone everyone has to have. So many features have been added and hardware upgrades as well. I have a 2.5G iPhone and many people have asked me "are you going to get the new iPhone?" and being a geek, the latest and greatest toys are always the best. With the 2.5G iPhone I let my brain take back seat to my credit card, BUT Im letting my brain take over on this one and stop me from spending $299 on a white 16G iPhone 3G. There are plenty more reasons than the financial.

 

Shared features, improved localization

The 3G iPhone is getting tons of improvements. The App Store, 3G (benched at 2x current iPhones EDGE speed @ WWDC), A-GPS, Exchange support, email attachments, search contacts just to name a few.

So we've got all these great features coming to us, awesome. But all 2.5G iPhones get the firmware 2.0 upgrade free. So we all get…App Store, Exchange support, email attachments, searching contacts. That only leaves us with A-GPS and 3G for another $300! So, we have Google maps triangulation, its not that good but it gets you close, plus no turn by turn directions. However the new iPhone with its GPS wont get that either. So what exactly is the point of knowing where in a 100ft circle you are, I've always been able to get from where I am to where I am going with "current location". So I'm counting that out of the pros.

 

3G

But the iPhone 3G gets its name from ATTs 3G wireless data network, faster internet, awesome! For almost everyone, this is a huge improvement. For me, not so much, 9 months out of the year I am attending school at MTU in Houghton, Mi. We barely get coverage up there let alone are we CLOSE to 3G coverage, and until ATT bought Dobson (cellular one) we could only get Alltel or Cell One phones, any other phones would be quickly de-contracted for being out of your 'home' usage area. So 3/4ths of my year, I'm going to be in an EDGE only zone anyway. Well, Ill be in a mostly Wi-Fi zone, at home and school I have Wi-Fi and I rarely need the data network elsewhere. So why should I pay $10 more per month for the same data and losing my 200 free texts? If the U.P. of Michigan gets 3G (or good cell phone coverage period) it would be more worth it, but for email away from Wi-Fi, streaming my music from home EDGE isn't that bad. YouTube is the only app I would like to see improvement on, but I use that…once a month.

 

2.5G still kickin' strong

Those being the big reasons, there are plenty of other reasons I am, and others will stick to the iPhone 2.5G. I bought my iPhone pretty soon after it was released and got an 8Gig phone. I have about 32Gigs of music so my Zune was keeping me happy until I broke that 30Gig mark, and my iPhone doesn't even get close to holding all my music for me. There is of course the argument that I'm not going to listen to days worth of music before I have the ability to re-sync my iPhone. This is very true, but what if I sync something, and I'm in the mood for a different style, 8Gigs doesn't give me much flexibility. To solve this and not care about the size of my phone all together I use Orb on my home server. I won't get into a big post about orb, but basically it lets me stream my Movies/Recorded TV shows/Music and best yet, live TV shows from my computer to my phone (or Xbox 360, or another computer, or WM phone, or…you get the idea). Since orb automatically sets the bit rate to something that my connection can handle it allows me to stream decent quality music to my iPhone while I drive anywhere, my iPhone now has access to 2TB worth of data. Video when I'm on Wi-Fi and audio anywhere.

The only REAL reason I would get the iPhone 3G over my EDGE version is the flush headphone jack. But Im working out the details of a mod right now so hopefully I can wipe that off the pros board. Even with that, there is not enough new and amazing to make the iPhone 3G worth it.

Posted 30 June 2008 10:59 AM by cmsears | 5 comment(s)
Filed under: , , , , ,
Charlie who?

I did it, I started a blog. And I’ve gotta say, these first blog posts are pretty hard. There is the tried and true “about me” blog post, and there is the tactic of just writing a blog post like it’s a second post. But the fact of the matter is, this isn’t a second blog post. There may be people reading this that have no clue who I am or why they should care. So I’m gonna have to follow the trend.

 

Who the heck is Charlie Sears?

Short answer: I am, and I’m awesome. Long answer: I’m the guy in the picture on the right. I’m a 20 year old Software Engineering major at Michigan Tech and interning at SRT Solutions. At school the majority of my code is Java/C++ and at work I do a lot of .Net development with ASP.NET and C#. When I’m just working on personal projects I use C# (and love LINQ, life without is overrated). I’m also VERY interested in learning F# (saw Dustin Campbell give a talk at CodeMash and was fascinated) and will be starting some research into that soon. I’m a pretty big video game player too, TF2, CS:S, AoC, WoW are all my addictions right now. I’ve been into computers since I was very little, though the first piece of electronics that fascinated me was the garage door opener. I’ve been coding since I was 11, C was my first language.

 

Ok, I know who you are now. Why the heck should I care?

Short answer: I’m awesome, I’ve said it before. Long answer: Get my name out there, and I’m sure there are people who care about the same things I do. Plus I have great hair, I promise not to blog TOO much about that. I’ve got my opinions, everyone does, and I think there are at least…4-5 people out there (that’s a scientific number, I promise) who care about what I have to say. I’m still in school and learning a ton so I don’t know if a lot of what I have to say will be amazing news to anyone. But I like to stay on the front of my learning and will be posting about things I find interesting. I won’t always post about software development.

 

Ok, you still have me, but I’m a bit confused about what you will talk about.

I won’t tell you I’m awesome here, you know that by now. But I’m going to talk about things that interest me and involve computers. New language features I find out about, new hardware, video games, life as an intern/student. For the most part Ill focus on things that plug in and how we make them do what we want, and how they don’t do what we want. I use computers in every part of my life to store media, for fun, for

 

More posts to come soon. Let me know what you think.

Charlie Sears

Charlie is a student studying Software Engineering at Michigan Tech and an Intern at SRT Solutions

Search

Go

This Blog

Syndication

Twitter




Follow me