MrNewbie
@MrNewbie
Мешаю водку с пивом

Как на C# запустить поочередно несколько потоков (РЕШЕНО)?

Изучаю многопоточность. Столкнулся со следующей проблемой. Вот такой код:
public class WORK{
        private int number;
        public Action<int> delegWork; // Обобщ.делегат
 
        public void Working(int num){
                this.number += num; // Какая-то полезная работа с результатов переданным в this.number
                ThreadPool.QueueUserWorkItem((object n) => { this.delegWork((int)n); }, this.number ); //Запуск делегата
        }
}
 
public class ANALYSIS{
        private readonly Form _form;  // Windows Form
        public Action<int> delegAnalysis; // Обобщ.делегат
 
        public ANALYSIS(Form form){
                this._form = form;
                this.Make();
        }
        
        // Метод класса, в котором происходит присвоение делегату анон.метода
        private void Make(){
                this.delegAnalysis += (number) => {
                      this._form.Invoke((MethodInvoker)delegate{
                           Thread.Sleep(25);  // Эмуляция полезной работы
                           Console.WriteLine ("Number: " + number);
                      });
                };
        }        
}
.....
 
/* В основном потоке */
 
WORK worker = new WORK();
ANALYSIS analyzer = new ANALYSIS(this); // В конструктор передаем текущий Windows Form приложения 
 
 
worker.delegWork += (number) => { analyzer.delegAnalysis(number); };
 
//Цикл в основном потоке (например построчное чтение из файла и т.п.)
for(int i = 0; i < 500; i++){
        worker.Working(i);
}


Описание кода — в методе Working класса WORK делается какая-то полезная работа, далее результат этой работы посредством делегатов delegWork и delegAnalysis отправляется в анон.метод класса ANALYSIS в котором производится анализ результатов работы класса WORK. Соответсвенно сама работа может выполняться быстрее, чем ее анализ, но сам анализ должен идти строго поочередно друг за другом, а не хаотично. Т.е. следующий вызванный метод через delegAnalysis должен дождаться результатов работы предыдущего вызова delegAnalysis.

Многопоточность реализовал с помощью ThreadPool.QueueUserWorkItem т.к. он более экономичный. В данном случаем Console.WriteLine отрабатывает в каком-то отдельном потоке/потоках и в консоле я вижу примерно следующее:
1
3
6
4
2
5
...
500
489
499

Как можно заметить, цифры следуют не по порядку.

Вопрос таков — как мне сделать поочередное исполнение потоков ? Чтобы следующий поток ожидал пока предыдущий не закончит свою работу. И желательно как можно менее ресурсоемко.

PS. На данный момент присматриваюсь к рекурсии и что-то вроде Task Continuewith (или await/join), но как собрать и обернуть все во едино сообразить не могут.

На данный момент решил таким образом:
С использованием BlockingCollection и запуском второго потока в конструкторе при инициализации класса WORK.
public class WORK{
        private BlockingCollection<Func<Task>> _collection = new BlockingCollection<Func<Task>>();
        private Thread ConsumerThread;
 
        private int number;
        public Action<int> delegWork; // Обобщ.делегат
        
        //Конструктор
        public WORK(){
                this.ConsumerThread = new Thread(this.LaunchThread);
                this.ConsumerThread.Start();
        }
 
        public void Working(int num){
                this.number += num; // Какая-то полезная работа с результатов переданным в this.number
                int index = this.number; this._collection.Add(new Func<Task>(async () => { this.delegWork(index); })); // Добавляем делегат во второй поток через BlockingCollection
        }
        
        // Метод для второго потока 
        private async void LaunchThread()
        {
            while (true)
            {
                var processTask = this._collection.Take();
                await Task.Run(processTask);
            }
        }
}
 
public class ANALYSIS{
        private readonly Form _form;  // Windows Form
        public Action<int> delegAnalysis; // Обобщ.делегат
 
        public ANALYSIS(Form form){
                this._form = form;
                this.Make();
        }
        
        // Метод класса, в котором происходит присвоение делегату анон.метода
        private void Make(){
                this.delegAnalysis += (number) => {
                      this._form.Invoke((MethodInvoker)delegate{
                           Console.WriteLine ("Number in analyzer: " + number);
                      });
                };
        }        
}
.....
 
/* В основном потоке */
 
WORK worker = new WORK();
ANALYSIS analyzer = new ANALYSIS(this); // В конструктор передаем текущий Windows Form приложения 
 
//Подписываем делегат
worker.delegWork += (number) => { analyzer.delegAnalysis(number); };
worker.delegWork += (number) => { Console.WriteLine ("Number: " + number); };
 
//Второй поток для задачи (например построчное чтение из файла и т.п.)
new Thread(() =>
{
     for(int i = 0; i < 500; i++){
             worker.Working(i);
     }
}).Start();
  • Вопрос задан
  • 1465 просмотров
Пригласить эксперта
Ответы на вопрос 2
Griboks
@Griboks Куратор тега C#
Вопрос таков — как мне сделать поочередное исполнение потоков ? Чтобы следующий поток ожидал пока предыдущий не закончит свою работу. И желательно как можно менее ресурсоемко.

Ниже приведён самый оптимальный вариант:
//Цикл в основном потоке
for(int i = 0; i < 500; i++) Console.WriteLine(i);
Ответ написан
@FFoxDiArt
Вы уж определитесь, что вам нужно: либо параллельно выполнять, либо последовательно. Зачем создавать параллельный код, который будет вести себя как последовательный, но с диким overhead'ом?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы