Re[6]: Ручная реализация очереди потоков
От: GuyFawkes  
Дата: 23.12.09 09:51
Оценка: :)
Здравствуйте, Аноним
Проблема в том, что я не совсем понимаю, как это сделать ) Кроме того, ThreadPool тормозит UI. Как решить эти проблемы, подскажите.
Ручная реализация очереди потоков
От: GuyFawkes  
Дата: 22.12.09 12:24
Оценка:
Доброе время суток, господа.
Мне необходимо вручную реализовать очередь потоков на C# с использованием BackgroundWorker. Суть идеи такова: есть главный поток (назовем его управляющим), внутри которого расположен бесконечный цикл, создающий потоки (также реализуемые при помощи BackgroundWorker) по мере необходимости. Для простоты имеет два "этапа" работ, и по завершении всех потоков для первого этапа необходимо начинать потоки для второго. Одновременно могут выполняться, скажем, не более 10 потоков. При завершении одного из этого десятка нужно сразу же запустить еще, дабы их количество пребывало постоянно, пока не исчерпаются индексы в списке (пусть это будет List<String>), с которым эти потоки работают. Естественно, существует некая переменная i, которая передается как аргумент в RunWorkerAsync для текущего создаваемого потока и представляет из себя индекс в вышеупомянутом списке.
Моя реализация содержит ошибку, которую я не могу исправить и которая приводит к тому, что переход ко второму "этапу" работ не происходит. При необходимости — выложу.
Подскажите идеи по реализации данной очереди. Заранее благодарен.
c# bsckgroundworker многопоточность
Re: Ручная реализация очереди потоков
От: mrjeka Россия  
Дата: 22.12.09 13:39
Оценка:
Здравствуйте, GuyFawkes, Вы писали:

GF>Доброе время суток, господа.

GF>Мне необходимо вручную реализовать очередь потоков на C# с использованием BackgroundWorker. Суть идеи такова: есть главный поток (назовем его управляющим), внутри которого расположен бесконечный цикл, создающий потоки (также реализуемые при помощи BackgroundWorker) по мере необходимости. Для простоты имеет два "этапа" работ, и по завершении всех потоков для первого этапа необходимо начинать потоки для второго. Одновременно могут выполняться, скажем, не более 10 потоков. При завершении одного из этого десятка нужно сразу же запустить еще, дабы их количество пребывало постоянно, пока не исчерпаются индексы в списке (пусть это будет List<String>), с которым эти потоки работают. Естественно, существует некая переменная i, которая передается как аргумент в RunWorkerAsync для текущего создаваемого потока и представляет из себя индекс в вышеупомянутом списке.
GF>Моя реализация содержит ошибку, которую я не могу исправить и которая приводит к тому, что переход ко второму "этапу" работ не происходит. При необходимости — выложу.
GF>Подскажите идеи по реализации данной очереди. Заранее благодарен.

Посмотрите ThreadPool
Re[2]: Ручная реализация очереди потоков
От: GuyFawkes  
Дата: 22.12.09 13:43
Оценка:
Я так понял, что он мне не подходит — я не понял, как в нем дождаться окончания текущего потока и, соответственно, узнать о том, что все потоки окончены. Кроме того, будет ли он "тормозить" интерфейс?
Re[3]: Ручная реализация очереди потоков
От: Codechanger Россия  
Дата: 22.12.09 13:51
Оценка:
Здравствуйте, GuyFawkes, Вы писали:

GF>Я так понял, что он мне не подходит — я не понял, как в нем дождаться окончания текущего потока и, соответственно, узнать о том, что все потоки окончены. Кроме того, будет ли он "тормозить" интерфейс?


Что-нить про AutoResetEvent слышали?
Re[4]: Ручная реализация очереди потоков
От: GuyFawkes  
Дата: 23.12.09 08:26
Оценка:
Codechanger, слышал. Но какой смысл мне вручную переписывать по сути тот же самый функционал backgroundWorker, если ThreadPool никак не может упростить мне задачу? Возможно, вы все же дадите какие-то замечания по следующему коду:


            BackgroundWorker main = new BackgroundWorker();
            main.DoWork += DoWorkersWatcher;
            main.RunWorkerCompleted += new RunWorkerCompletedEventHandler(main_RunWorkerCompleted);
            main.RunWorkerAsync(1);

так я по щелчку, к примеру, на кнопку запустил "управляющий" поток

        private void DoWorkersWatcher(object s, DoWorkEventArgs args)
        {
            Int32 WorkType = Convert.ToInt32(args.Argument.ToString());
            workers.Clear();
            int i = 0;
            while (true)
            {
                // вынести одинаковое в процедуры - писалось без оптимизации для чистой наглядности по ходу разработки
                switch (WorkType)
                {
                    case 1:
                        if (QueryCounter == rpList.Count)
                        {
                            workers.Clear();
                            WorkType++;
                            QueryCounter = 0;
                            CurrentThreadCount = 0;
                            i = 0;
                            break;
                        }
                        if ((CurrentThreadCount < MaxThreadsCount) && (i <= rpList.Count))
                        {
                            BackgroundWorker bw = new BackgroundWorker();
                            bw.DoWork += DoSaveFirstInfoWork;
                            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted1);
                            workers.Add(bw);
                            bw.RunWorkerAsync(i);
                            CurrentThreadCount++;
                            i++;
                        }
                        break;
                    case 2:
                        if (QueryCounter == rpList.Count)
                        {
                            WorkType++;
                            break;
                        }
                        if ((CurrentThreadCount < MaxThreadsCount) && (i <= rpList.Count))
                        {
                            BackgroundWorker bw = new BackgroundWorker();
                            bw.DoWork += DoSavePageInfoWork;
                            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted2);
                            workers.Add(bw);
                            bw.RunWorkerAsync(i);
                            CurrentThreadCount++;
                            i++;
                        }
                        break;
                }
                if (WorkType == 9)
                {
                    args.Result = "finished";
                    return;
                }
            }
        }



а в обработке RunWorkerCompleted в конце стоят строки

            QueryCounter++;
            CurrentThreadCount--;
Re[5]: Ручная реализация очереди потоков
От: Аноним  
Дата: 23.12.09 09:44
Оценка:
Здравствуйте, GuyFawkes, Вы писали:

GF>Codechanger, слышал. Но какой смысл мне вручную переписывать по сути тот же самый функционал backgroundWorker, если ThreadPool никак не может упростить мне задачу? Возможно, вы все же дадите какие-то замечания по следующему коду:



GF>а в обработке RunWorkerCompleted в конце стоят строки


GF>
GF>            QueryCounter++;
GF>            CurrentThreadCount--;
GF>



может не в тему и не все понял. но вы увеличиваете QueryCounter и CurrentThreadCount не потокобезопасно Вам необходимо еспользовать
InterlockedIncrement/InterlockedDekcrement. И вот так просто проверять условие в котором находятся изменияемые из разных потоков переменные.
Может какую блокировку ввести/захватить на сей момент?


У вас проверка QueryCounter идет в потоке основного BackgroundWOrker'a. а RunWorkerCompleted в другом потоке исполняется (не в основном BackgroundWorker'e)).

В чем проблема сделать тоже самое на тредпуле стандартном.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.