Как мне ждать, пока все остальные потоки завершат свои задачи? - PullRequest
2 голосов
/ 24 декабря 2010

У меня есть несколько потоков, потребляющих задачи из очереди, используя что-то похожее на код ниже. Проблема заключается в том, что существует один тип задач, который не может быть запущен во время обработки других задач.

Вот что у меня есть:

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();
}

И это то, что мне нужно:

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();
}

Проблема в том, что я не знаю, как этого добиться, не создавая беспорядка.

Ответы [ 4 ]

1 голос
/ 24 декабря 2010

Попробуйте использовать TreadPool, а затем метод WaitHandle.WaitAll, чтобы определить, что все потоки завершили выполнение.

MSDN

0 голосов
/ 24 декабря 2010

Вы можете думать об этом как о структуре данных, которая позволяет любому количеству читателей или одному писателю. То есть любое количество потоков может считывать структуру данных, но поток, который записывает в структуру данных, нуждается в монопольном доступе.

В вашем случае вы можете использовать любое количество «обычных» потоков или один поток, который требует монопольного доступа.

.NET имеет классы ReaderWriterLock и ReaderWriterLockSlim, которые вы можете использовать для реализации этого типа совместного использования. К сожалению, ни один из этих классов не доступен на xbox.

Однако можно реализовать блокировку чтения / записи из комбинации объектов Monitor и ManualResetEvent. У меня нет примера C # (зачем мне, так как у меня есть доступ к нативным объектам?), Но есть простая реализация Win32 , которую не очень сложно портировать.

0 голосов
/ 24 декабря 2010

WaitHandle.WaitAll (autoEvents); Может быть, это то, что вы хотите.

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;
        }
    }
0 голосов
/ 24 декабря 2010

вы можете использовать что-то вроде этого,

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");
    }

Надеюсь, эта помощь.

...