Реализация прогресса выполнения задачи с отдельных потоков - 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;
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

14   голосов , оценка 3.857 из 5
Похожие ответы