运行线程字符串生成器以附加csv时生成的重复项

时间:2016-02-25 12:48:40

标签: c# multithreading

我有一个ping清扫程序,可以在已定义的ip范围内的任何有效设备上恢复基本的snmp信息,并将这些结果附加到stringbuilder csv,但我似乎得到了一些重复项,如前三个:

Date    IP  Site    MAC Manufacturer    Model   Serial
25/02/2016  10.65.10.8  CS  00:00:AA:C2:24:AC   Dell    Dell 7130cdn    XDH100611
25/02/2016  10.65.10.4  CS  00:00:AA:C2:24:AC   Dell    Dell 7130cdn    XDH100611
25/02/2016  10.65.10.3  CS  00:00:AA:C2:24:AC   Dell    Dell 7130cdn    XDH100611
25/02/2016  10.65.10.9  CS  00:00:AA:C2:3A:57   Dell    Dell 7130cdn    XDH100746
25/02/2016  10.65.10.11 CS  00:15:99:48:64:33   Dell    Dell 5330dn Mono Laser Printer  1ZG2FG1
25/02/2016  10.65.10.12 CS  00:15:99:45:93:70   Dell    Dell 5330dn Mono Laser Printer  2HC2FG1

似乎在多线程运行时有时变量会在一个线程中更新,最终我会将重复写入csv。是否有更好的方法将变量包含在自己的线程中?我可以在全球范围内定义变量吗?下面是示例代码:

static void Main(string[] args)
    {

        var header = string.Format("{0},{1},{2},{3},{4},{5},{6}{7}", "Date", "IP", "Site", "MAC", "Manufacturer","Model", "Serial", Environment.NewLine);
        csv.Append(header);

        string[] sites = { "65" };

        foreach (string site in sites)
        {
            string ipBase = "10." + site + ".10.";
            for (int i = 1; i < 255; i++)
            {
                string ip = ipBase + i.ToString();
                Ping p = new Ping();
                p.PingCompleted += new PingCompletedEventHandler(p_PingCompleted);
                countdown.AddCount();
                p.SendAsync(ip, 100, ip);
                Thread.Sleep(10);
            }
        }            
        File.WriteAllText("Printers.csv", csv.ToString());
        File.WriteAllText("Exceptions.csv", exception.ToString());
        Console.ReadLine();
    }

static void p_PingCompleted(object sender, PingCompletedEventArgs e)
    {
        string ip = (string)e.UserState;
        if (e.Reply != null && e.Reply.Status == IPStatus.Success)
        {
            string host = ip;
            string community = "public";

            SimpleSnmp snmp = new SimpleSnmp(host, community);
            if (!snmp.Valid)
            {
                exception.Append(string.Format("{0},{1},{2}{3}", DateTime.Now.ToString("dd-MM-yy"), ip, "SNMP agent host name/ip address is invalid.", Environment.NewLine));
            }
            Dictionary<Oid, AsnType> result = snmp.Get(SnmpVersion.Ver1,
                                                      new string[] { ".1.3.6.1.2.1.1.1.0" });
            if (result == null)
            {
                exception.Append(string.Format("{0},{1},{2}{3}", DateTime.Now.ToString("dd-MM-yy"), ip, "no snmp result", Environment.NewLine));
            }
            else
            {
                    TRYONE(ip);
            }

            lock (lockObj)
            {
                upCount++;
            }
        }
    }

public static string WhatSite(string site)
    {
        string[] sitecode = site.Split('.');


        if (sitecode[1] == "65")
        {
            site = "CS";
            return site;
        }
        else
        {
            return "xx";
        }
    }

static void TRYONE (string ip)
    {
        string host = ip;
        string community = "public";
        model = "";
        serial = "";
        macaddress = "";

        SimpleSnmp snmp = new SimpleSnmp(host, community);

        if (!snmp.Valid)
        {
            exception.Append(string.Format("{0},{1},{2}{3}", DateTime.Now.ToString("dd-MM-yy"), ip, "SNMP agent host name/ip address is invalid.", Environment.NewLine));
            return;
        }
        Dictionary<Oid, AsnType> result = snmp.Get(SnmpVersion.Ver1,
            new string[] { ".1.3.6.1.2.1.25.3.2.1.3.1", ".1.3.6.1.2.1.43.5.1.1.17.1", ".1.3.6.1.4.1.11.2.4.3.1.23.0" });                                      



        if (result == null)
        {
                exception.Append(string.Format("{0},{1},{2}{3}", DateTime.Now.ToString("dd-MM-yy"), ip, "No results received?", Environment.NewLine));
                return;
        }
        else
        {
            foreach (KeyValuePair<Oid, AsnType> kvp in result)
            {
                if (kvp.Key.ToString() == "1.3.6.1.2.1.25.3.2.1.3.1")
                {
                    model = kvp.Value.ToString();
                    if (model.Contains(";"))
                    {
                        string[] temp = model.Split(';');
                        model = temp[0];
                    }                     
                }
                if (kvp.Key.ToString() == "1.3.6.1.2.1.43.5.1.1.17.1")
                {
                    serial = kvp.Value.ToString();

                }
                if (kvp.Key.ToString() == "1.3.6.1.4.1.11.2.4.3.1.23.0")
                {
                    macaddress = kvp.Value.ToString();
                    macaddress = macaddress.Replace(" ", ":");
                }

            }

            string[] manufacturer = model.Split(' ');

            Console.WriteLine("{0} {1} {2} {3} {4} {5}", ip, manufacturer[0], model, serial, macaddress, WhatSite(ip));

            csv.Append(string.Format("{0},{1},{2},{3},{4},{5},{6}{7}", DateTime.Now.ToString("dd-MM-yy"), ip, WhatSite(ip), macaddress, manufacturer[0], model, serial, Environment.NewLine));

        }
    }

由于

1 个答案:

答案 0 :(得分:2)

  

有没有更好的方法将变量包含到自己的线程中?我可以非全局定义变量吗?

您可以在全局上下文中定义变量,但可以使用ThreadLocal<T>将其用途限制在自己的线程中。

但是,在您的情况下,您似乎想要组合多个线程的输出。实现此结果的一种方法是设置一对全局ConcurrentQueue<string>对象,一个用于csv,一个用于exception,并且各个线程写入这些队列。然后主线程将等待工作线程完成,逐个读取两个队列中的字符串,并将结果写入文件。