views:

3104

answers:

12

I have a bit of code that I need to run in a different thread than the GUI as it currently causes the form to freeze whilst the code runs (10 seconds or so). I have never created a new thread before so I'm after a basic example (as simple as possible) of how to do this in C# .Net 2.0. Could someone please post an example?

Many thanks

+14  A: 

Try using the BackgroundWorker class. You give it delegates for what to run, and to be notified when work has finished. There is an example on the MSDN page that I linked to.

Andy
You can certainly do this with the Thread class, but BackgroundWorker gives you methods for thread completion and progress reporting that you'd otherwise have to figure out how to use yourself. Don't forget that you have to use Invoke to talk to the UI!
Robert Rossney
Be warned: BackgroundWorker has some subtle limitations, but for the common "I want to go away and do something and have my form stay responsive" it's fantastic.
Merus
+8  A: 

Quick and dirty, but it will work:

Using at top:

using System.Threading;

simple code:

static void Main( string[] args )
{
    Thread t = new Thread( NewThread );
    t.Start();
}

static void NewThread()
{
    //code goes here
}

I just threw this into a new console application for an exmaple

TJMonk15
-1. At a minimum you would need to set IsBackground to true.
Remember threads flagged IsBackground are not automatically terminated by the Runtime. This requires thread management by the app. If you leave the thread marked as not background then after the threads execution the thread is terminated for you.
CmdrTallen
+1 for quick and dirty
Lucas B
@CmdrTallen: That's not quite right. A thread marked IsBackground=true means that thread won't stop the process from exiting i.e. a process will exit when all threads with IsBackground=false have exited
Phil Devaney
+8  A: 

The ThreadPool.QueueUserWorkItem is pretty ideal for something simple. The only caveat is accessing a control from the other thread.

System.Threading.ThreadPool.QueueUserWorkItem(delegate {
    DoSomethingThatDoesntInvolveAControl();
}, null);
Mark Brackett
+1  A: 

Put that code in a function (the code that can't be executed on the same thread as the GUI), and to trigger that code's execution put the following.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Calling the start function on the thread object will cause the execution of your function call in a new thread.

Redbaron
-1. At a minimum you would need to set IsBackground to true.
A: 

another option, that uses delegates and the Thread Pool...

assuming 'GetEnergyUsage' is a method that takes a DateTime and another DateTime as input arguments, and returns an Int...

// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method 
GetEnergyUsageDelegate nrgDel = GetEnergyUsage;                     
IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
while (!aR.IsCompleted) Thread.Sleep(500);
int usageCnt = nrgDel.EndInvoke(aR);
Charles Bretana
Charles, is your code functionally different from `int usageCnt = nrgDel.Invoke(lastRunTime, procDT, null, null);` ? It looks like it suspends current thread with sleep anyway... I thought it will help nothing with GUI freeze if you call it in GUI thread
IgorK
Yes, BeginInvoke calls the delegate on another thread from thread pool... If you use Invoke, the delegate is called syncronously on the current thread... But you're right, the sleep is wrong... you should eliminate that and collect the results using a callback function. I'll edit to show that
Charles Bretana
A: 

How to: Use a Background Thread to Search for Files

You have to be very carefull with access from other threads to GUI specific stuff (it is common for many GUI toolkits). If you want to update something in GUI from processing thread check this answer that I think is useful for WinForms. For WPF see this (it shows how to touch component in UpdateProgress() method so it will work from other threads, but actually I don't like it is not doing CheckAccess() before doing BeginInvoke through Dispathcer, see and search for CheckAccess in it)

Was looking .NET specific book on threading and found this one (free downloadable). See http://www.albahari.com/threading/ for more details about it.

I believe you will find what you need to launch execution as new thread in first 20 pages and it has many more (not sure about GUI specific snippets I mean strictly specific to threading). Would be glad to hear what community thinks about this work 'cause I'm reading this one. For now looked pretty neat for me (for showing .NET specific methods and types for threading). Also it covers .NET 2.0 (and not ancient 1.1) what I really appreciate.

IgorK
A: 

There are many ways of running separate threads in .Net, each has different behaviors. Do you need to continue running the thread after the GUI quits? Do you need to pass information between the thread and GUI? Does the thread need to update the GUI? Should the thread do one task then quit, or should it continue running? The answers to these questions will tell you which method to use.

There is a good async method article at the Code Project web site that describes the various methods and provides sample code.

Dour High Arch
+2  A: 
// following declaration of delegate ,,,
public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, 
                                            DateTime procDateTime);

// following inside of some client method 

    GetEnergyUsageDelegate nrgDel = GetEnergyUsage;                     
    IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null);
    while (!aR.IsCompleted) Thread.Sleep(500);
    int usageCnt = nrgDel.EndInvoke(aR);

Charles your code(above) is not correct. You do not need to spin wait for completion. EndInvoke will block until the WaitHandle is signaled.

If you want to block until completion you simply need to

nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null));

or alternatively

ar.AsyncWaitHandle.WaitOne();

But what is the point of issuing anyc calls if you block? You might as well just use a synchronous call. A better bet would be to not block and pass in a lambda for cleanup:

nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null);

One thing to keep in mind is that you must call EndInvoke. A lot of people forget this and end up leaking the WaitHandle as most async implementations release the waithandle in EndInvoke.

Matt Davison
A: 

If you are going to use the raw Thread object then you need to set IsBackground to true at a minimum and you should also set the Threading Apartment model (probably STA).

 public static void DoWork()
 {
  // do some work
 }

 public static void StartWorker()
 {
  Thread worker = new Thread(DoWork);
  worker.IsBackground = true;
  worker.SetApartmentState(System.Threading.ApartmentState.STA);
  worker.Start()    
 }

I would recommend the BackgroundWorker class if you need UI interaction.

A: 

I'd recommend looking at Jeff Richter's Power Threading Library and specifically the IAsyncEnumerator. Take a look at the video on Charlie Calvert's blog where Richter goes over it for a good overview.

Don't be put off by the name because it makes asynchronous programming tasks easier to code.

Robert Paulson
+3  A: 

BackgroundWorker seems to be best choice for you.

Here is my minimal example. After you click on the button the background worker will begin working in background thread and also report its progress simultaneously. It will also report after the work completes.

    private void button1_Click(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();

        // this allows our worker to report progress during work
        bw.WorkerReportsProgress = true;

        // what to do in the background thread
        bw.DoWork += new DoWorkEventHandler(
        delegate(object o, DoWorkEventArgs args)
        {
            BackgroundWorker b = o as BackgroundWorker;

            // do some simple processing for 10 seconds
            for (int i = 1; i <= 10; i++)
            {
                // report the progress in percent
                b.ReportProgress(i * 10);
                Thread.Sleep(1000);
            }

        });

        // what to do when progress changed (update the progress bar for example)
        bw.ProgressChanged += new ProgressChangedEventHandler(
        delegate(object o, ProgressChangedEventArgs args)
        {
            label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
        });

        // what to do when worker completes its task (notify the user)
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
        delegate(object o, RunWorkerCompletedEventArgs args)
        {
            label1.Text = "Finished!";
        });

        bw.RunWorkerAsync();
    }

Note:

  • I put everything in single method using C#'s anonymous method for simplicity but you can always pull them out to different methods.
  • It is safe to update GUI within ProgressChanged or RunWorkerCompleted handlers. However, updating GUI from DoWork will cause InvalidOperationException.
m3rLinEz
A: 

If you want to get a value:

var someValue;

Thread thread = new Thread(delegate()
            {                 
                //Do somthing and set your value
                someValue = "Hello World";
            });

thread.Start();

while (thread.IsAlive)
  Application.DoEvents();