Здравствуйте, Аноним
Проблема в том, что я не совсем понимаю, как это сделать ) Кроме того, ThreadPool тормозит UI. Как решить эти проблемы, подскажите.
Доброе время суток, господа.
Мне необходимо вручную реализовать очередь потоков на C# с использованием BackgroundWorker. Суть идеи такова: есть главный поток (назовем его управляющим), внутри которого расположен бесконечный цикл, создающий потоки (также реализуемые при помощи BackgroundWorker) по мере необходимости. Для простоты имеет два "этапа" работ, и по завершении всех потоков для первого этапа необходимо начинать потоки для второго. Одновременно могут выполняться, скажем, не более 10 потоков. При завершении одного из этого десятка нужно сразу же запустить еще, дабы их количество пребывало постоянно, пока не исчерпаются индексы в списке (пусть это будет List<String>), с которым эти потоки работают. Естественно, существует некая переменная i, которая передается как аргумент в RunWorkerAsync для текущего создаваемого потока и представляет из себя индекс в вышеупомянутом списке.
Моя реализация содержит ошибку, которую я не могу исправить и которая приводит к тому, что переход ко второму "этапу" работ не происходит. При необходимости — выложу.
Подскажите идеи по реализации данной очереди. Заранее благодарен.
Здравствуйте, GuyFawkes, Вы писали:
GF>Доброе время суток, господа. GF>Мне необходимо вручную реализовать очередь потоков на C# с использованием BackgroundWorker. Суть идеи такова: есть главный поток (назовем его управляющим), внутри которого расположен бесконечный цикл, создающий потоки (также реализуемые при помощи BackgroundWorker) по мере необходимости. Для простоты имеет два "этапа" работ, и по завершении всех потоков для первого этапа необходимо начинать потоки для второго. Одновременно могут выполняться, скажем, не более 10 потоков. При завершении одного из этого десятка нужно сразу же запустить еще, дабы их количество пребывало постоянно, пока не исчерпаются индексы в списке (пусть это будет List<String>), с которым эти потоки работают. Естественно, существует некая переменная i, которая передается как аргумент в RunWorkerAsync для текущего создаваемого потока и представляет из себя индекс в вышеупомянутом списке. GF>Моя реализация содержит ошибку, которую я не могу исправить и которая приводит к тому, что переход ко второму "этапу" работ не происходит. При необходимости — выложу. GF>Подскажите идеи по реализации данной очереди. Заранее благодарен.
Я так понял, что он мне не подходит — я не понял, как в нем дождаться окончания текущего потока и, соответственно, узнать о том, что все потоки окончены. Кроме того, будет ли он "тормозить" интерфейс?
Здравствуйте, GuyFawkes, Вы писали:
GF>Я так понял, что он мне не подходит — я не понял, как в нем дождаться окончания текущего потока и, соответственно, узнать о том, что все потоки окончены. Кроме того, будет ли он "тормозить" интерфейс?
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)).
В чем проблема сделать тоже самое на тредпуле стандартном.