How can I wait for a thread to finish with .NET?

前端 未结 10 2148
有刺的猬
有刺的猬 2020-11-22 10:27

I\'ve never really used threading before in C# where I need to have two threads, as well as the main UI thread. Basically, I have the following.

public void S         


        
相关标签:
10条回答
  • 2020-11-22 10:55

    If using from .NET 4 this sample can help you:

    class Program
    {
        static void Main(string[] args)
        {
            Task task1 = Task.Factory.StartNew(() => doStuff());
            Task task2 = Task.Factory.StartNew(() => doStuff());
            Task task3 = Task.Factory.StartNew(() => doStuff());
            Task.WaitAll(task1, task2, task3);
            Console.WriteLine("All threads complete");
        }
    
        static void doStuff()
        {
            // Do stuff here
        }
    }
    

    From: Create multiple threads and wait all of them to complete

    0 讨论(0)
  • 2020-11-22 10:55

    When I want the UI to be able to update its display while waiting for a task to complete, I use a while-loop that tests IsAlive on the thread:

        Thread t = new Thread(() => someMethod(parameters));
        t.Start();
        while (t.IsAlive)
        {
            Thread.Sleep(500);
            Application.DoEvents();
        }
    
    
    0 讨论(0)
  • 2020-11-22 11:06

    I can see five options available:

    1. Thread.Join

    As with Mitch's answer. But this will block your UI thread, however you get a Timeout built in for you.


    2. Use a WaitHandle

    ManualResetEvent is a WaitHandle as jrista suggested.

    One thing to note is if you want to wait for multiple threads: WaitHandle.WaitAll() won't work by default, as it needs an MTA thread. You can get around this by marking your Main() method with MTAThread - however this blocks your message pump and isn't recommended from what I've read.


    3. Fire an event

    See this page by Jon Skeet about events and multi-threading. It's possible that an event can become unsubcribed between the if and the EventName(this,EventArgs.Empty) - it's happened to me before.

    (Hopefully these compile, I haven't tried)

    public class Form1 : Form
    {
        int _count;
    
        void ButtonClick(object sender, EventArgs e)
        {
            ThreadWorker worker = new ThreadWorker();
            worker.ThreadDone += HandleThreadDone;
    
            Thread thread1 = new Thread(worker.Run);
            thread1.Start();
    
            _count = 1;
        }
    
        void HandleThreadDone(object sender, EventArgs e)
        {
            // You should get the idea this is just an example
            if (_count == 1)
            {
                ThreadWorker worker = new ThreadWorker();
                worker.ThreadDone += HandleThreadDone;
    
                Thread thread2 = new Thread(worker.Run);
                thread2.Start();
    
                _count++;
            }
        }
    
        class ThreadWorker
        {
            public event EventHandler ThreadDone;
    
            public void Run()
            {
                // Do a task
    
                if (ThreadDone != null)
                    ThreadDone(this, EventArgs.Empty);
            }
        }
    }
    

    4. Use a delegate

    public class Form1 : Form
    {
        int _count;
    
        void ButtonClick(object sender, EventArgs e)
        {
            ThreadWorker worker = new ThreadWorker();
    
            Thread thread1 = new Thread(worker.Run);
            thread1.Start(HandleThreadDone);
    
            _count = 1;
        }
    
        void HandleThreadDone()
        {
            // As before - just a simple example
            if (_count == 1)
            {
                ThreadWorker worker = new ThreadWorker();
    
                Thread thread2 = new Thread(worker.Run);
                thread2.Start(HandleThreadDone);
    
                _count++;
            }
        }
    
        class ThreadWorker
        {
            // Switch to your favourite Action<T> or Func<T>
            public void Run(object state)
            {
                // Do a task
    
                Action completeAction = (Action)state;
                completeAction.Invoke();
            }
        }
    }
    

    If you do use the _count method, it might be an idea (to be safe) to increment it using

    Interlocked.Increment(ref _count)

    I'd be interested to know the difference between using delegates and events for thread notification, the only difference I know are events are called synchronously.


    5. Do it asynchronously instead

    The answer to this question has a very clear description of your options with this method.


    Delegate/Events on the wrong thread

    The event/delegate way of doing things will mean your event handler method is on thread1/thread2 not the main UI thread, so you will need to switch back right at the top of the HandleThreadDone methods:

    // Delegate example
    if (InvokeRequired)
    {
        Invoke(new Action(HandleThreadDone));
        return;
    }
    
    0 讨论(0)
  • 2020-11-22 11:07

    I took a little different approach. There is a counter option in previous answers, and I just applied it a bit differently. I was spinning off numerous threads and incremented a counter and decremented a counter as a thread started and stopped. Then in the main method I wanted to pause and wait for threads to complete I did.

    while (threadCounter > 0)
    {
        Thread.Sleep(500); // Make it pause for half second so that we don’t spin the CPU out of control.
    }
    

    This is documented in my blog post: http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/

    0 讨论(0)
提交回复
热议问题