简体   繁体   中英

How do I wait for all other threads to finish their tasks?

I have several threads consuming tasks from a queue using something similar to the code below. The problem is that there is one type of task which cannot run while any other tasks are being processed.

Here is what I have:

while (true) // Threaded code
{
    while (true)
    {
        lock(locker)
        {
            if (close_thread)
                return;

            task = GetNextTask(); // Get the next task from the queue
        }

        if (task != null)
            break;

        wh.WaitOne(); // Wait until a task is added to the queue
    }

    task.Run();
}

And this is kind of what I need:

while (true)
{
    while (true)
    {
        lock(locker)
        {
            if (close_thread)
                return;

            if (disable_new_tasks)
            { 
                task = null; 
            }
            else
            {
                task = GetNextTask();
            }
        }

        if (task != null)
            break;

        wh.WaitOne();
    }

    if(!task.IsThreadSafe())
    {
        // I would set this to false inside task.Run() at 
        // the end of the non-thread safe task
        disable_new_tasks = true;  
        Wait_for_all_threads_to_finish_their_current_tasks(); 
    }

    task.Run();
}

The problem is I don't know how to achive this without creating a mess.

Try looking to using a TreadPool and then using the WaitHandle.WaitAll method to determine that all threads have finished executing.

MSDN

WaitHandle.WaitAll(autoEvents); Maybe this is what you want.

class Calculate
    {
        double baseNumber, firstTerm, secondTerm, thirdTerm;
        AutoResetEvent[] autoEvents;
        ManualResetEvent manualEvent;

        // Generate random numbers to simulate the actual calculations.
        Random randomGenerator;

        public Calculate()
        {
            autoEvents = new AutoResetEvent[]
            {
                new AutoResetEvent(false),
                new AutoResetEvent(false),
                new AutoResetEvent(false)
            };

            manualEvent = new ManualResetEvent(false);
        }

        void CalculateBase(object stateInfo)
        {
            baseNumber = randomGenerator.NextDouble();

            // Signal that baseNumber is ready.
            manualEvent.Set();
        }

        // The following CalculateX methods all perform the same
        // series of steps as commented in CalculateFirstTerm.

        void CalculateFirstTerm(object stateInfo)
        {
            // Perform a precalculation.
            double preCalc = randomGenerator.NextDouble();

            // Wait for baseNumber to be calculated.
            manualEvent.WaitOne();

            // Calculate the first term from preCalc and baseNumber.
            firstTerm = preCalc * baseNumber * 
                randomGenerator.NextDouble();

            // Signal that the calculation is finished.
            autoEvents[0].Set();
        }

        void CalculateSecondTerm(object stateInfo)
        {
            double preCalc = randomGenerator.NextDouble();
            manualEvent.WaitOne();
            secondTerm = preCalc * baseNumber * 
                randomGenerator.NextDouble();
            autoEvents[1].Set();
        }

        void CalculateThirdTerm(object stateInfo)
        {
            double preCalc = randomGenerator.NextDouble();
            manualEvent.WaitOne();
            thirdTerm = preCalc * baseNumber * 
                randomGenerator.NextDouble();
            autoEvents[2].Set();
        }

        public double Result(int seed)
        {
            randomGenerator = new Random(seed);

            // Simultaneously calculate the terms.
            ThreadPool.QueueUserWorkItem(
                new WaitCallback(CalculateBase));
            ThreadPool.QueueUserWorkItem(
                new WaitCallback(CalculateFirstTerm));
            ThreadPool.QueueUserWorkItem(
                new WaitCallback(CalculateSecondTerm));
            ThreadPool.QueueUserWorkItem(
                new WaitCallback(CalculateThirdTerm));

            // Wait for all of the terms to be calculated.
            **WaitHandle.WaitAll(autoEvents);**

            // Reset the wait handle for the next calculation.
            manualEvent.Reset();

            return firstTerm + secondTerm + thirdTerm;
        }
    }

You can think of this as similar to a data structure that allows any number of readers, or one writer. That is, any number of threads can read the data structure, but a thread that writes to the data structure needs exclusive access.

In your case, you can have any number of "regular" threads running, or you can have one thread that requires exclusive access.

.NET has the ReaderWriterLock and ReaderWriterLockSlim classes that you could use to implement this kind of sharing. Unfortunately, neither of those classes is available on the xbox.

However, it possible to implement a reader/writer lock from a combination of Monitor and ManualResetEvent objects. I don't have a C# example (why would I, since I have access to the native objects?), but there's a simple Win32 implementation that shouldn't be terribly difficult to port.

you can use something like this,

ExecutorService workers = Executors.newFixedThreadPool(10); 

   for(int i=0; i<input.length; i++) {
       Teste task = new Teste(rowArray,max);//your thread class
       workers.execute(task);
   }

   workers.shutdown();//ask for shut down
   while(!workers.isTerminated()) {//wait until all finishes.

  try {
      Thread.sleep(100);//
      } catch (InterruptedException exception) {
      }   
      System.out.println("waiting for submitted task to finish operation");
    }

Hope this help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM