402

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

Assume I have never created a new thread before; what's a simple/basic example of how to do this in C# and using .NET Framework 2.0 or later?

p.campbell
  • 98,673
  • 67
  • 256
  • 322
  • 4
    Most of the answers here were good at the time, but improvements in .NET Framework 4.0 make things simpler. You can use the Task.Run() method, as described in this answer: https://stackoverflow.com/a/31778592/1633949 – Richard II Oct 25 '19 at 13:49

15 Answers15

415

Good place to start reading is Joe Albahari.

If you want to create your own thread, this is as simple as it gets:

using System.Threading;
new Thread(() => 
{
    Thread.CurrentThread.IsBackground = true; 
    /* run your code here */ 
    Console.WriteLine("Hello, world"); 
}).Start();
Ed Power
  • 8,310
  • 3
  • 36
  • 42
  • @EdPower, does this apply only to Winforms.. or will it work in Web Forms..? – MethodMan Jan 28 '16 at 03:31
  • @MethodMan - Yes, it'll work in Web Forms. [Start here:](http://stackoverflow.com/questions/14296188/how-to-use-threads-in-asp-net) – Ed Power Jan 28 '16 at 19:11
  • 21
    Be careful about setting `IsBackground` to true. It probably does not do what you think it does. What it does, is configure whether the thread will be killed when all foreground threads have died, or whether the thread will keep the application alive. If you don't want your thread terminated mid-execution, do not set `IsBackground` to true. – Zero3 Sep 22 '16 at 13:34
  • Docs: https://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.110).aspx#Anchor_2 – Zero3 Sep 22 '16 at 13:34
  • Actually, @Zero3, I'd be more careful about not setting 'IsBackground' to 'true', which I wish was the default for new threads. As noted in your documentation link, even thread pool threads (and thus async tasks) are also background threads . And I've never had a case where I wanted to leave a thread running after the app or service terminated. – Ed Power Sep 22 '16 at 16:38
  • 14
    @EdPower I think you should be careful either way! One example of a task that you probably don't want to terminate mid-execution is one that saves data to disk. But sure, if your task is suitable for termination at any time, the flag is fine. My point was just that *one needs to be careful about using the flag*, since you did not describe its purpose, and its naming could easily lead one to believe that it does something else than what it actually does. – Zero3 Sep 23 '16 at 08:44
  • 6
    with .NET Framework 4.0+ just use Task.Run(), as described in this answer: https://stackoverflow.com/a/31778592/1633949 – Richard II Oct 25 '19 at 13:58
  • @RichardII Absolutely true! However, not for every use case; if you want control over the stack size of a thread, you'd have to stick with `Thread`. – Zimano Dec 15 '19 at 14:52
196

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.

using System.ComponentModel;
...
    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.
Will Bickford
  • 5,381
  • 2
  • 30
  • 45
Gant
  • 29,661
  • 6
  • 46
  • 65
  • 28
    Using System.ComponentModel; (might save people from doing a google search, thanks for this helpful code example) +1 – sooprise Mar 07 '11 at 19:04
  • @Gant Thank you for the sample code. When i tried your code the ProgressChanged event was not firing. However when i tried the similar accepted answer here[http://stackoverflow.com/questions/23112676/background-worker-reportprogress-not-firing] it worked. – Martin Sep 04 '14 at 12:47
  • 1
    @sooprise Ctrl + . helps you in these situations! (Assuming you're using Visual Studio) – SepehrM Nov 13 '14 at 18:20
103

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
  • 84,552
  • 17
  • 108
  • 152
  • Also my favorite. One quick line for the _junction_. I have it on speed dial (snippet). Works very well with Controls. You just need to know how to use [Invoke](http://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx) and [InvokeRequired](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx). – Bitterblue Jul 08 '14 at 11:34
  • 1
    +1 Note that the delegate allows you to wrap parameters neatly as well. – Will Bickford Aug 21 '14 at 19:17
  • how to use ThreadPool.QueueUserWorkItem with callback function means when job done then call back will notify us. – Mou Feb 22 '17 at 12:27
93

Here is another option:

Task.Run(()=>{
//Here is a new thread
});
Spongebob Comrade
  • 1,495
  • 2
  • 17
  • 32
  • 1
    if you create a thread this way, how would u stop this thread from the UI thread? – slayernoah May 06 '16 at 17:44
  • 1
    @slayernoah you can pass a CancellationTokenSource as a parameter to it and set the cancellation token outside the thread: https://msdn.microsoft.com/en-us/library/dd997364(v=vs.110).aspx – Spongebob Comrade May 09 '16 at 02:35
  • 17
    This code will not guarantee you to have a new thread. The decision is up to the current implementation of the ThreadPool you are using. See as example https://stackoverflow.com/questions/13570579/is-it-possible-always-to-force-a-new-thread-with-task – Giulio Caccin Sep 05 '17 at 12:51
  • 8
    @GiulioCaccin It is possible for ThreadPool to choose an existing thread from its pool but it is definitely a different thread. – Spongebob Comrade Sep 18 '17 at 03:58
86

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

FallenAvatar
  • 4,079
  • 1
  • 21
  • 24
  • 9
    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 Mar 16 '09 at 14:29
  • 16
    @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 Aug 06 '09 at 15:42
40

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
  • 30,088
  • 6
  • 78
  • 89
  • 6
    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 Dec 12 '08 at 18:49
  • 1
    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 Jan 28 '09 at 00:49
  • 11
    @Merus, could you expand on what those subtle limitations are? – Christian Hudon Sep 18 '12 at 20:34
14

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();
sth
  • 222,467
  • 53
  • 283
  • 367
6

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,038
  • 1
  • 10
  • 13
  • 3
    @user50612 What are you talking about? The new thread will run `nameOfFunction` in the background, and not on the current GUI thread. The `IsBackground` property determines whether the thread will keep the application alive or not: https://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.110).aspx#Anchor_2 – Zero3 Sep 22 '16 at 13:29
5

Here how can use threads with a progressBar , its just for understing how the threads works, in the form there are three progressBar and 4 button:

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    Thread t, t2, t3;
    private void Form1_Load(object sender, EventArgs e)
    {

        CheckForIllegalCrossThreadCalls = false;

         t = new Thread(birinicBar); //evry thread workes with a new progressBar


         t2 = new Thread(ikinciBar);


         t3 = new Thread(ucuncuBar);

    }

    public void birinicBar() //to make progressBar work
    {
        for (int i = 0; i < 100; i++) {
            progressBar1.Value++;
            Thread.Sleep(100); // this progressBar gonna work faster
        }
    }

    public void ikinciBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar2.Value++;
            Thread.Sleep(200);
        }


    }

    public void ucuncuBar()
    {
        for (int i = 0; i < 100; i++)
        {
            progressBar3.Value++;
            Thread.Sleep(300);
        }
    }

    private void button1_Click(object sender, EventArgs e) //that button to start the threads
    {
        t.Start();
        t2.Start(); t3.Start();

    }

    private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar
    {
        t.Suspend();
        t2.Suspend();
        t3.Suspend();
    }

    private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping
    {
        t.Resume();
        t2.Resume();
        t3.Resume();
    }

    private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads
    {
        t.Abort();
        t2.Abort();
        t3.Abort();
    }
}
Ammar Alyasry
  • 106
  • 1
  • 6
4
// 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.

JHobern
  • 866
  • 1
  • 13
  • 20
Matt Davison
  • 1,544
  • 10
  • 11
4

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.

JHobern
  • 866
  • 1
  • 13
  • 20
user50612
  • 3,098
  • 3
  • 25
  • 20
  • Be careful about setting IsBackground to true. It probably does not do what you think it does. What it does, is configure whether the thread will be killed when all foreground threads have died, or whether the thread will keep the application alive. If you don't want your thread terminated mid-execution, do not set IsBackground to true. – Zero3 Sep 22 '16 at 13:35
  • Docs: https://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.110).aspx#Anchor_2 – Zero3 Sep 22 '16 at 13:36
1

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
  • 143,358
  • 22
  • 150
  • 216
  • 1
    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 Dec 12 '08 at 17:45
  • 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 Dec 12 '08 at 17:54
1

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.

Note this article was written before the async/await pattern and Task Parallel Library were introduced into .NET.

Dour High Arch
  • 21,513
  • 29
  • 75
  • 90
0

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.

Community
  • 1
  • 1
IgorK
  • 886
  • 9
  • 26
0

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
  • 17,603
  • 5
  • 34
  • 53