3

If you have one main thread that starts two other threads. what is the cleanest way to make the primary thread wait for the two other threads?

I could use bgndworker and sleep spinner that checks for both the bgnd workers's IsBusy, but I would think there's a better way.

EDIT Some more requirements:

  • The main thread has some other work to do (e.g. GUI).
  • The two spawned threads should be able to report exceptions and return result values
Boris Callens
  • 90,659
  • 85
  • 207
  • 305

6 Answers6

10

Quick example using Thread.Join();

        Thread t1 = new Thread(new ThreadStart(delegate()
        {
            System.Threading.Thread.Sleep(2000);
        }));

        Thread t2 = new Thread(new ThreadStart(delegate()
        {
            System.Threading.Thread.Sleep(4000);
        }));

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

EDIT Another 3example using Wait Handles:

            ManualResetEvent[] waitHandles = new ManualResetEvent[]{
            new ManualResetEvent(false),
            new ManualResetEvent(false)
        };

        Thread t1 = new Thread(new ParameterizedThreadStart(delegate(object state)
        {
            ManualResetEvent handle = (ManualResetEvent)state;
            System.Threading.Thread.Sleep(2000);
            handle.Set();
        }));

        Thread t2 = new Thread(new ParameterizedThreadStart(delegate(object state)
        {
            ManualResetEvent handle = (ManualResetEvent)state;
            System.Threading.Thread.Sleep(4000);
            handle.Set();
        }));

        t1.Start(waitHandles[0]);
        t2.Start(waitHandles[1]);

        WaitHandle.WaitAll(waitHandles);

        Console.WriteLine("Finished");
REA_ANDREW
  • 10,666
  • 8
  • 48
  • 71
  • The second exaple could help me out, I'll have a look into it – Boris Callens Feb 27 '09 at 10:43
  • Is there a way to use the resetevents with the backgroundworker? – Boris Callens Feb 27 '09 at 10:48
  • Subscribe to the BackgroundWorker's RunWorkerCompleted which is fired when the task is complete, cancelled or raises an exception – REA_ANDREW Feb 27 '09 at 10:52
  • That would require my ManualResetEvent[] to be global. – Boris Callens Feb 27 '09 at 10:55
  • Ok, another option i could advise which is still asyncronous, is the MethodInvoker class which you code a callback method which is called when the function completes MethodInvoker m = new MethodInvoker(MyMethod); BeginInvoke and EndInvoke . You are able to provide state too. Sounds more suited – REA_ANDREW Feb 27 '09 at 11:00
5

See the answers on this thread. I like this option ;-p

Forker p = new Forker();
p.Fork(delegate { DoSomeWork(); });
p.Fork(delegate { DoSomeOtherWork(); });
p.Join();

Re returning values / reporting exceptions - just have each fork do that as a callback at the end of the logic... (you can use captured variables to pass state into both the forks, including a shared logger etc).

Community
  • 1
  • 1
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
3
thread1.Join();
thread2.Join();
James L
  • 16,456
  • 10
  • 53
  • 70
1

In addition to the other answers... one alternative to "start two threads and wait for both to finish" is "start one thread and do one job yourself, then wait for the other thread to finish".

Of course, if you want to start two jobs, do some more work on the main thread and then wait for the two other threads to finish, that doesn't work so well.

EDIT: If the main thread is a UI thread, you shouldn't be blocking on the other threads finishing - you should (IMO) get them to call back to the main thread when they've finished. That way you'll still have a responsive UI while they're executing.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes, valid point. But maybe I oversimplified the question. The main thread will be busy with updating the UI so can't be bothered with the IO heavy tasks. – Boris Callens Feb 27 '09 at 10:45
  • The main thread is a Console thread. It will show some repetetive "Waiting..." message. But I follow you on events over spinning. See my other question: http://stackoverflow.com/questions/594329/define-backgroundworkers-runworkercompleted-with-an-anonymous-method Or am I going completely off track? – Boris Callens Feb 27 '09 at 11:05
1

You can't wait for finish and have GUI usable. The best approach for this is to spawn threads and use events to communicate with GUI. Remember, that in the event handler you cannot modify control. Rather that doing it directly, use Invoke method.

Migol
  • 8,161
  • 8
  • 47
  • 69
  • Usually also one needs some info back to the GUI so that the use of events for progress info cannot be avoided if you don't want the thread to be autistic. This answer is the best I could read on this page thanks! – jdehaan Sep 10 '09 at 10:47
0

WaitHandle.WaitAny is your friend. It lets you wait on multiple threads or other kinds of objects to be signaled.

http://msdn.microsoft.com/en-us/library/tdykks7z.aspx

EDIT:

Actually, WaitHandle.WaitAll is what you want, not WaitAny.

http://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitall.aspx

EDIT:

The Join method some mention is ok, but one drawback is that it's not an completely atomic operation. This may or may not be important to you, though.

Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • In my current situation it doesn't matter THAT much, but I try to get a main idea out of every question so I can apply it later on when other problems occure. So yes, it is important in some way. – Boris Callens Feb 27 '09 at 11:07