Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.01.2019, 12:42   #1
SuprSonic
Пользователь
 
Регистрация: 07.08.2016
Сообщений: 16
Вопрос Как запустить поочередно несколько потоков?

Изучаю многопоточность. Столкнулся со следующей проблемой. Имеется такой вот гипотетический код:
Код:
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);
}
Многопоточность реализовал с помощью ThreadPool.QueueUserWorkItem т.к. он более экономичный. В данном случаем Console.WriteLine отрабатывает в каком-то отдельном потоке/потоках и в консоле я вижу примерно следующее:
Код:
1
3
6
4
2
5
...
500
489
499
Как можно заметить, цифры следуют не по порядку.

Вопрос такой — Как мне сделать поочередное исполнение потоков строго в той последовательности в которой они создавались? Желательно как можно менее ресурсоемко.

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

PS. Lock и AutoResetEvent пробовал, но не помогло. Т.к. там доступ/событие получает тот поток, который первый постучался. Соответсвенно стучатся они, опять же, не в том порядке в котором были созданы, а как решит сама система.
SuprSonic вне форума Ответить с цитированием
Старый 16.01.2019, 21:18   #2
SuprSonic
Пользователь
 
Регистрация: 07.08.2016
Сообщений: 16
По умолчанию

На данный момент нашел такое решение с использованием 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);
             if(i==50) Thread.Sleep(10000); // Эмулируем очень сложную работу на 50-й строчке
     }
}).Start();
SuprSonic вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как запустить приложение несколько раз? Trip Помощь студентам 2 04.09.2011 18:28
Пишу сканер протов. Как сделать в несколько потоков? Dasharnb777 Общие вопросы .NET 2 17.11.2010 11:05