Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > Многопоточность в фоновом потоке. Запутался


Автор: Bladerender 31.5.2011, 15:51
Итак задача (переделанная из специфической в объекты, понятные всем). 
Назовём её так. "Многопоточный сбор состояния экипажа танка"
Есть у нас конвеер, на котором движутся танки. В танках уже сидит экипаж (роботы). У этих роботов есть коллекция модулей, у которых в парарельных потоках нужно опросить их состояние. Т.е. грубо говоря у модуля есть метод Ready(), который вернет пригодность или нет. 

Танк -> роботы -> Начинка роботов. При чем опрос танков на конвеере и опрос роботов в танке проходит не паралельно а один за другим, а именно опрос модулей робота в танке - многопоточно.  В каждом роботе может быть разное количество модулей. В среднем 8-15. Опрос каждого модуля ~ 200мс. И не хотелось бы использовать что-то типа Тред.Слип(). Хочу архитектурку чисто event based...

Вроде все вводные предоставил. Преступим. 

В идеологии должно бы было это работать. БекграундВоркер запускает в фоновом потоке метод ПроверитьВсеТанки(). 
ПроверитьВсеТанки() перебирает танки по одному и вызывает их проверку (через публичный метод класа Танк). 
Метод ПроверитьТанк() берет первого члена своего экипажа и запускает метод проверки модулей ПроверитьРобота(). 
ПроверитьРобота перебирает все модули, запуская для проверки каждого модуля свой тред. Каждый тред вернет результат в обработчик ивента и как только общее количество результатов совпадет с количеством модулей  - вызовется метод ПроверитьТанк() с следующим членом экипажа. 



Итак. Есть метод ПроверитьВсеТанки() который привязан к BackGroundWorker. Весь процесс начинается с backgroundworker.RunWorkerAsync();



Код


ПроверитьВсеТанки()
{
  foreach(танк Танк in танки)
  {
     танк.Проверить().
  }
}


class Танк
{
     List<робот> экипаж;
     private Робот _текущийЧленЭкипажа = -1.
     List<object> _результатыПроверки;
     int _количествоМодулей = -1; 

  public void ПроверитьТанк()
     {
         _текущийЧленЭкипажа +=1;
         if(_текущийЧленЭкипажа=экипаж.Length)
         {return;}

         Робот текущийРобот = экипаж[ _текущийЧленЭкипажа];
          
         РезультатыПроверки.Clear();
         ПроверитьРобота(текущийРобот.Модули)
         
     }

 private void Проверитьробота(Модули[] модули)
    {

       _количествоМодулей =  модули.Count;
       
        for(int i =0;i<модули.Count;i++)
        {
           
          ПроверяльщикМодулей проверяльщикМодулей = new ПроверяльщикМодулей();
          ПроверяльщикМодулей.Checked += new ПроверяльщикМодулей.CheckedHandler(ПроверяльщикМодулей_Checked);          

             Thread t = new Thread(delegate() 
                         {
                               ПроверяльщикМодулей.ПроверитьМодуль(модули[i])
                        });
                    t.Start();
         }
    }


 void ПроверяльщикМодулей_Checked(object sender, List<object> parametrs)
        {
            _результатыПроверки.Add(sender);

            if(_коливествоМодулей.Count==_результатыПроверки.Count)
            {
                 _текущийЧленЭкипажа +=1;
                this.ПроверитьТанк().
            }
        }
}


Сам проверяльщик модулей описывать бумаю не стоит, что бы не загромождать. Обычный класс, который замаячит обработчику событий ПроверяльщикМодулей_Checked о том, что переданный модуль проверен. После этого проверяльщик умирает, так как для каждого модуля создается свой экземпляр проверяльщика. 

Где у меня бок? Бок в том, что метод ПроверитьРобота() отправляет на проверку модули и заканчивается, что приводит к тому, что он возвращает проверяльщику танка, что я выполнился и можно отправлять на проверку следующий танк. Как справится - не очень понимаю. Сразу напрашивается - сделать ивент у Танка, что бы он срабатывал в том месте, где у меня return; ()типа там где кончился экипаж. Только вот проблемы это как бы не снимает, так как метод ПроверитьВсеТанки() всеравно побырику отправит все танки на проверку и бекграундВоркер схлопнется  smile . НА листике рисовал - вроде все работает и так и эдак. Но на практике сразу впираюсь на очевидный бок и что с ним делать - хз. Помогите советом. 










Автор: vlsaf 31.5.2011, 16:03
На вскидку. 

Ты же должен дождаться выполнения потоков. А для этого поток, котрый запускает другие потоки должен ждать, а не идти дальше, не дождавшись выполнения. 

Кури Join()

Автор: gambit 1.6.2011, 10:32
Цитата(vlsaf @  31.5.2011,  16:03 Найти цитируемый пост)
Ты же должен дождаться выполнения потоков. А для этого поток, котрый запускает другие потоки должен ждать, а не идти дальше, не дождавшись выполнения. 

Не скажу на сколько этот ответ верен, ибо вопрос не осилил. Но если это то, то посмотри такую штуку как барьеры.

Автор: Bladerender 1.6.2011, 13:39
Join() решает. Спасибо.  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)