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

前端 未结 10 2297
有刺的猬
有刺的猬 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 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 or Func
            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;
    }
    

提交回复
热议问题