C#:多线程(WMI)应用程序锁定GUI

时间:2014-09-25 11:39:57

标签: c# multithreading user-interface network-programming wmi

我想知道是否有人对我在下面的代码中遇到的问题有任何指导。代码的目的是:

  • 加载1000台计算机的列表
  • 使用WMI和Parallel.foreach()从他们那里收集信息
    • 将此信息写入磁盘
  • 使用每台计算机状态更新主GUI中的列表视图

我遇到的问题是连接到大约1000台计算机后,主GUI应用程序锁定。为了避免明显的GUI锁定我一直在使用Invoke()来更新主GUI。

这个错误很难在测试环境中重现,因为它在连接到如此多的计算机之后发生。我对这个bug的想法是它可能是以下之一(我不是专家):

  • 我使用多线程/ Parallel.foreach()
  • 犯了一个菜鸟错误
  • 调用Invoke()的次数太多,主GUI一直忙于更新
  • 我已经使用了程序的所有可用资源(机器似乎有更多可用的RAM)
  • 在远程计算机上完成的处理速度太慢(WAN链接) - 为什么会影响主GUI?

以下是代码,它以 ScanButton_Click()开头:

&# 13;

namespace WMIScan
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        // ...Other code removed as it is irrelevant

        private void ScanButton_Click(object sender, EventArgs e)
        {
            /*
             * Scan all computers in the list
             */
            List<string> computers = new List<string>();
            foreach (ListViewItem item in CompList1.Items)
            {
                computers.Add(item.Text);
                item.SubItems[1].Text = "";
                item.SubItems[2].Text = "";
                item.SubItems[3].Text = "";
            }
            LaunchScanning(computers);
        }

        private void LaunchScanning(List<string> computers)
        {
            /*
             * This function is responsible for launching a scan against all computers in the list
             * It handles the multithreading of scan jobs.
             */
            toolStripProgressBar1.Minimum = 0;
            toolStripProgressBar1.Value = 0;
            toolStripProgressBar1.Maximum = computers.Count;
            System.Threading.Tasks.Task Processing;

            //Support the scanning of multiple computers.
            toolStripStatusLabel1.Text = "Scanning of " + computers.Count + " computers(s) started at: " + DateTime.Now;
            Processing = Task.Factory.StartNew(() =>
                {
                    Parallel.ForEach(computers, new ParallelOptions { MaxDegreeOfParallelism = max_threads }, computer =>
                    {
                        BeginScanning(computer);
                        toolStripProgressBar1.GetCurrentParent().BeginInvoke(new MethodInvoker(delegate { toolStripProgressBar1.Value++; }));
                    });
                    toolStripStatusLabel1.Text = "Scanning of " + computers.Count + " computers(s) completed.";
                }
            );
            
        }

        private void BeginScanning(string computer)
        {
            /*
             * This function is responsible for conducting the scanning of a single computer
             */
            ManagementScope cimv2_scope = new ManagementScope();
            ConnectionOptions options = new ConnectionOptions();
            ObjectQuery query;
            ManagementObjectSearcher searcher;
            ManagementObjectCollection queryCollection;
            System.IO.StreamWriter file = null;
            string completed_jobs = "";
            string errors = "";
            string[] listview_output = { "", "","" };

            //Check if credentials have been provided.
            if (username != "" && password != "")
            {
                options.Username = username;
                options.Password = password;
            }

            //Attempt inital connection
            cimv2_scope = new ManagementScope(@"\\" + computer + @"\root\CIMV2", options);
            try
            {
                //Create new scope connections
                cimv2_scope.Connect();

                //Attempt to open output file.
                try
                {
                    file = new System.IO.StreamWriter(output_dir + @"\" + computer + ".txt");
                    file.WriteLine("######Start " + DateTime.Now);

                    //Query Operating System
                    try
                    {
                        query = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
                        searcher = new ManagementObjectSearcher(cimv2_scope, query);
                        queryCollection = searcher.Get();
                        foreach (ManagementObject m in queryCollection)
                        {
                            DateTime InstallDate = ManagementDateTimeConverter.ToDateTime(m["InstallDate"].ToString());
                            DateTime LastBootUpTime = ManagementDateTimeConverter.ToDateTime(m["LastBootUpTime"].ToString());
                            DateTime LocalDateTime = ManagementDateTimeConverter.ToDateTime(m["LocalDateTime"].ToString());
                            file.WriteLine("OS," + computer + "," + m["CSName"] + "," + m["BuildNumber"] + "," + m["Caption"]
                                + "," + m["Version"] + "," + m["OSArchitecture"] + "," + m["ServicePackMajorVersion"] + ","
                                + m["ServicePackMinorVersion"] + "," + m["CurrentTimeZone"] + "," + InstallDate + "," +
                                LastBootUpTime + "," + LocalDateTime + "," + m["OSLanguage"] + "," + m["OSProductSuite"] +
                                "," + m["OSType"] + "," + m["RegisteredUser"] + "," + m["SerialNumber"] + "," + m["SystemDevice"]
                                + "," + m["SystemDirectory"] + "," + m["SystemDrive"] + "," + m["WindowsDirectory"]);
                        }
                        completed_jobs = "OS";
                    }
                    catch (Exception e)
                    {
                        errors += ("[Operating System] " + e.Message);
                    }

                    // ... Many more WMI queries here
                   
                    //Processing completed
                    file.WriteLine("Completed " + DateTime.Now);
                    file.Close();

                    CompList1.BeginInvoke(new MethodInvoker(delegate
                    {
                        ListViewItem tmp = CompList1.FindItemWithText(computer);
                        tmp.SubItems[1].Text = "True";
                        tmp.SubItems[2].Text = completed_jobs;
                        tmp.SubItems[3].Text = errors;
                    }));
                }
                catch (Exception e) //File Open Error
                {
                    CompList1.BeginInvoke(new MethodInvoker(delegate
                    {
                        ListViewItem tmp = CompList1.FindItemWithText(computer);
                        tmp.SubItems[1].Text = "Failed";
                        tmp.SubItems[2].Text = "";
                        tmp.SubItems[3].Text = e.Message;
                    }));
                }
            }
            catch (Exception e) //Scope Connection Error
            {
                CompList1.BeginInvoke(new MethodInvoker(delegate
                {
                    ListViewItem tmp = CompList1.FindItemWithText(computer);
                    tmp.SubItems[1].Text = "Failed";
                    tmp.SubItems[2].Text = "";
                    tmp.SubItems[3].Text = e.Message;
                }));
            }
        }
     }
}
&#13;
&#13;
&#13;

我是C#和StackOverflow的新手,非常感谢任何帮助!

谢谢,

乔丝

1 个答案:

答案 0 :(得分:-1)

据我所知,Parallel.ForEach与你拥有的核心数量有关。即。如果你有4个核心,你将能够并行处理4个线程。

为什么不做foreach并为您希望处理的每个操作创建一个Task。 (我没有对此进行过测试,但你明白了这一点)

var tasks = new List<Task>();


    foreach(var computer in computers)
    {
      var t =Task.Factory.StartNew(() =>
                    {
                        BeginScanning(computer);

                         Acttion myUiStuff = () =>
                         {
                            toolStripProgressBar1.Value++;
                            toolStripStatusLabel1.Text = "Scanning of " + computers.Count + " computers(s) completed.";
                         };

                         //im assuming you are using WinForms; UI objects must be modified by UI thread so thats is the call to BeginInvoke; If its WPF call the Dispatcher.
                         BeginInvoke(myUiStuff);
                    }
      tasks.Add(t);
    }

    Task.WaitAll(tasks.ToArray());