First, let me say that you don't do multithreading unless it is absolutely necessary. Trying to avoid and optimize your code in the most proficient way will do somehow best, as you will avoid multhreading troubles.
Second, the BackgroundWorker class is a good start. You will need to instantiate as many instances as you require threads to be run. For each of them, you will have to code its DoWork() method. This method is called when you launch its operation by calling the BackgroundWorker.RunWorkerAsync() method. The code you want to place in the DoWork() event is the code that shall be asynchronously run in the background while your application's main thread gets busy with something else. The other two events : ProgressChanged() and RunWorkerCompleted() are used to ReportProgress() or to define what to do when the thread has done its job, whatever end it is (Exception, properly ended, etc.) I use BackgroundWorker most of the time, as it is, in my humble point of view, the simplest to be used.
Third, you can use the System.Threading.Thread class. It is a bit more complicated then just defining a DoWork() event and making it occur by calling another method. You will have to get acquainted with delegates. In short, delegates are types of method or function that are used to execute some work in the background. As for these delegates, you may have multiple methods of the same delegate type, as I just said, delegates are method types. You may have multiple references of a delegate. You may see it also as a method signature. Then, when comes the time to use it, you have to reference a method for the wanted delegate. Using the System.Threading.Thread class, you want to take an eye out on the ThreadStart delegate.
delegate void DoWork(object sender);
private void btnProcessWork_Click(object sender, EventArgs e) {
DoWork doWork = SimpleDoWorkMethod;
// Then start using the delegate.
Thread t = new Thread(new ThreadStart(doWork));
t.Start(); // Launch the thread in background...
// Do something else while the thread is working !!!
}
private void SimpleDoWorkMethod(object s) {
// Do some work here...
}
Fourth, think of delegates as an event, as Events are based on delegates. As a matter of fact, you provide a method that will be used to handle an event like the Button_Click(), for instance. To associate your btnProcess.Click event with your btnProcess_Click() method programmatically, you need to write:
btnProcess.Click += new EventHandler(btnProcess_Click);
What you do here is to make the btnProcess.Click event reference your btnProcess_Click() method. Notice the EventHandler delegate with the ThreadStart delegate. They serves quite the same purpose, but for two different reality (GUI event response and multithreading).
Fifth, don't forget to lock a variable before accessing it while another might want to access it at about the same time, then throwing a cross thread or so exception, and this, even for primitive types, but more specifically for collections, as they are not thread-safe.
Hope this helps a bit! =)