Реализация прогресса выполнения задачи с отдельных потоков - C#
Формулировка задачи:
Всем здравствуйте!
Опишу более подробно свою проблему, надеюсь большое количества текста не оттолкнёт.
Во многих своих приложениях я использую сканер локальной сети, некий самописный класс с подклассами, который за максимально короткое время должен выдать мне информацию о активных хостах в сети с максимальной точностью.
Для реализации я решил создать n-ное количество потоков (в основном для сканирования подсети с маской 24, а это 254 потока), записать их в некий список List и после этого запустить потоки на выполнение. В потоках, как нетрудно догадаться, проводится пинг хостов с определенными параметрами (вроде количества попыток, таймаута и т.д.)
И вот в чём проблема - мне нужно отслеживать некое события, назовём его Scan_Progress_Changed, которое вызывается каждый раз, когда прогресс сканирования изменяется хотя-бы на 1%. И по сути прогресс меняется при завершении каждого с потоков. Пока что я реализовал это таким образом: после запуска потоков на выполнение, в цикле foreach для каждого из потоков выполняется Join, после каждого с которых, соответственно, изменяется значение прогресса сканирования. Только вот цикл перебирает потоки последовательно, в то время как завершаться они могут в хаотичном порядке. Как результат - прогресс отображается рывками и ни о какой плавности и информативности речи быть не может.
Я пытался вызывать событие прямо под конец каждого с выполняемых потоков, но это не приводило ни к чему хорошему - мало того, что событие вызывалось не с основного потока (а этого бы хотелось), так еще и при попытке прикрутить ко всему этому какой-нибудь прогресс-бар, изменяя его значение через Invoke, весь этот каскад потоков зависал.
Направьте, пожалуйста, в правильное русло. Спасибо.
Решение задачи: «Реализация прогресса выполнения задачи с отдельных потоков»
textual
Листинг программы
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; using System.Threading.Tasks; using System.Net; using System.Net.NetworkInformation; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); button1.Click += new EventHandler(button1_Click); } void button1_Click(object sender, EventArgs e) { string[] addresses ={"50.18.212.157","50.18.212.223","107.23.48.232", "107.23.48.182","54.68.183.151","54.68.165.206", "54.67.52.245","54.67.48.128", "54.187.208.163" }; progressBar1.Value = 0; progressBar1.Maximum = addresses.Length; listBox1.Items.Clear(); Scanner scanner = new Scanner(); scanner.ScannerEvent += new EventHandler<ScannerEventArgs>(scanner_ScannerEvent); scanner.ScanParallel(addresses); } void scanner_ScannerEvent(object sender, ScannerEventArgs e) { listBox1.Invoke((Action)(() => { string result = string.Format("Address: {0}, Status: {1}", e.Address, e.Status); listBox1.Items.Add(result); })); progressBar1.Invoke((Action)(() => { progressBar1.Value++; })); } } public class Scanner { public event EventHandler<ScannerEventArgs> ScannerEvent; public void ScanParallel(string[] addresses) { Task.Factory.StartNew(() => { ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = addresses.Length }; Parallel.ForEach(addresses, options, address => { Ping ping = new Ping(); PingReply reply = ping.Send(address); OnScannerEvent(new ScannerEventArgs(reply.Address, reply.Status)); }); }); } protected virtual void OnScannerEvent(ScannerEventArgs e) { if (ScannerEvent != null) { ScannerEvent(this, e); } } } public class ScannerEventArgs : EventArgs { public readonly IPAddress Address; public readonly IPStatus Status; public ScannerEventArgs(IPAddress address, IPStatus status) { Address = address; Status = status; } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д