private void ScanIPTotal()
        {
            for (int i = 0; i < scanThreads.Length; i++)
            {
                
                    scanThreads[i] = new Thread(new ThreadStart(ScanIP));
                
                    scanThreads[i].IsBackground = true;
                    scanThreads[i].Start();
                
            }
        WaitIPScanFinish:
            Thread.Sleep(200);
            for (int i = 0; i < scanThreads.Length; i++)
            {
                if (scanThreads[i].ThreadState != ThreadState.Aborted && scanThreads[i].ThreadState != ThreadState.Stopped)
                {
                    Thread.Sleep(200);
                    goto WaitIPScanFinish;                          // 死循环等待所有扫描子线程结束
                }
                else 
                {
                }
            }
            ShowIPScanResult myShowIPScanResult = new ShowIPScanResult(Update_FinishIPScan);
            this.Invoke(myShowIPScanResult);           
        }
        private void ScanIP()
        {
        ScanLeftIP:
            string tmpIP="";
            lock (needScanIP)
            {
                if (needScanIP.Count > 0)
                {
                    tmpIP = needScanIP[needScanIP.Count - 1].ToString();
                    needScanIP.RemoveAt(needScanIP.Count - 1);
                }
                else
                {
                }
            }
            if (tmpIP != "")
            {
                if (PingHost.IpOnLine(tmpIP)==true)               // 判断在线
                {
                    lock(onlineIP)                                  // 锁住变量比锁住UI控件容易
                    {
                       
                        onlineIP.Add(tmpIP+"在线");
                        ShowIPScanResult uplsB = new ShowIPScanResult(Update_lsB_LiveHost);// 子线程一般不能直接修改UI,所以用这块委托(放外面可能会乱了)
                        this.Invoke(uplsB);
                    }
                }
                else
                {
                    lock (onlineIP)                                  // 锁住变量比锁住UI控件容易
                    {
                        onlineIP.Add(tmpIP + "未在线");
                        ShowIPScanResult uplsB = new ShowIPScanResult(Update_lsB_LiveHost);// 子线程一般不能直接修改UI,所以用这块委托(放外面可能会乱了)
                        this.Invoke(uplsB);
                    }
                }
                scanedIPCount ++;
                ShowIPScanResult upproBar = new ShowIPScanResult(Update_proBar_IPscan);
                this.Invoke(upproBar);
                goto ScanLeftIP;                                    // 死循环等待所有IP被扫描子完了,否则继续扫
            }
            else
            {
            }
        }代码是扫描1-255,在线IP,问题是:9是在线IP,扫描1-8,没问题未在线,但是扫描1-9,就变成全部在线了。

解决方案 »

  1.   

    没看出有什么问题,不过最前面的,不需要死循环等待线程技术,可以用Thread.Join 方法来等待所有线程结束,
      

  2.   

    输出的在先ip是不是都是相同的?我怀疑你把相同的ip写入needScanIP,
      

  3.   

    PingHost.IpOnLine方法内部是否使用了类变量,或者是静态变量,这个方法看起来是静态方法,用在多线程不是很好,最好写成实例方法,然后每个线程自己new一个实例来调用,
      

  4.   

    你把PingHost.IpOnLine代码贴出来看看,是怎样的?多半是这里出问题,
      

  5.   

    去掉goto 标签吧,
    容易造成死循环
    改用标记flag来标记线程情况
      

  6.   

    我在奇怪的是每个线程要扫描多少IP?看代码是是用needScanIP 和scanedIPCount 记录未扫描IP和已扫描IP。但是每个线程扫描的IP一样么?都从needScanIP这里取?
      

  7.   


    又仔细审了下代码,看懂是所有线程共同扫描一个IP集,每个线程扫描这个IP集的独立子集,从代码上看没有看到问题。所以同意7L意见,怀疑PingHost.IpOnLine。。
      

  8.   

    把PingHost.IpOline() 贴出来,大家看一下 public static bool IpOnLine(string des_ip)           // 用Ping.exe的方法实现
            {
                try
                {
                byte[] data = new byte[1024];
                int receive;
                Socket host = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
                IPEndPoint iep = new IPEndPoint(IPAddress.Parse(des_ip), 0);
                EndPoint ep = (EndPoint)iep;
                ICMP packet = new ICMP();
                packet.Type = 0x08;
                packet.Code = 0x00;
                packet.Checksum = 0;
                Buffer.BlockCopy(BitConverter.GetBytes((short)1), 0, packet.Message, 0, 2);
                Buffer.BlockCopy(BitConverter.GetBytes((short)1), 0, packet.Message, 2, 2);
                data = Encoding.ASCII.GetBytes("test packet");
                Buffer.BlockCopy(data, 0, packet.Message, 4, data.Length);
                packet.MessageSize = data.Length + 4;
                int packetsize = packet.MessageSize + 4;
                UInt16 chcksum = packet.getChecksum();
                packet.Checksum = chcksum;
                host.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 3000);
                host.SendTo(packet.getBytes(), packetsize, SocketFlags.None, iep);
               
                    data = new byte[1024];
                    receive = host.ReceiveFrom(data, ref ep);
                    host.Close();
                    return true;
                }
                catch 
                {
                    return false;
                }
            }
        }
        public class ICMP
        {
            public byte Type;
            public byte Code;
            public UInt16 Checksum;
            public int MessageSize;
            public byte[] Message = new byte[1024];
            public ICMP()
            {
            }
            public ICMP(byte[] data, int size)
            {
                Type = data[20];
                Code = data[21];
                Checksum = BitConverter.ToUInt16(data, 22);
                MessageSize = size - 24;
                Buffer.BlockCopy(data, 24, Message, 0, MessageSize);
            }
            public byte[] getBytes()
            {
                byte[] data = new byte[MessageSize + 9];
                Buffer.BlockCopy(BitConverter.GetBytes(Type), 0, data, 0, 1);
                Buffer.BlockCopy(BitConverter.GetBytes(Code), 0, data, 1, 1);
                Buffer.BlockCopy(BitConverter.GetBytes(Checksum), 0, data, 2, 2);
                Buffer.BlockCopy(Message, 0, data, 4, MessageSize);
                return data;
            }
            public UInt16 getChecksum()
            {
                UInt32 chcksm = 0;
                byte[] data = getBytes();
                int packetsize = MessageSize + 8;
                int index = 0;
                while (index < packetsize)
                {
                    chcksm += Convert.ToUInt32(BitConverter.ToInt16(data, index));
                    index += 2;
                }
                chcksm = (chcksm >> 16) + (chcksm & 0xffff);
                chcksm += (chcksm >> 16);
                return (UInt16)(~chcksm);
            }
      

  9.   

    其他的不看,很明显的一个问题。你里面的tmpIP没有lock啊
      

  10.   

    怎么改,将tmpIP lock就行了?试过了,没效果啊
      

  11.   

    你怎么改lock? 把tmpIP改成 class 级变量了?
      

  12.   

    你改成这样试试:
    private void ScanIP()
            {
            ScanLeftIP:
                string tmpIP="";
                lock (needScanIP)
                {
                    if (needScanIP.Count > 0)
                    {
                        tmpIP = needScanIP[needScanIP.Count - 1].ToString();
                        needScanIP.RemoveAt(needScanIP.Count - 1);
                    }
                    else
                    {
                    }if (tmpIP != "")
                {
                    if (PingHost.IpOnLine(tmpIP)==true)               // 判断在线
                    {
                        lock(onlineIP)                                  // 锁住变量比锁住UI控件容易
                        {
                           
                            onlineIP.Add(tmpIP+"在线");
                            ShowIPScanResult uplsB = new ShowIPScanResult(Update_lsB_LiveHost);// 子线程一般不能直接修改UI,所以用这块委托(放外面可能会乱了)
                            this.Invoke(uplsB);
                        }
                    }
                    else
                    {
                        lock (onlineIP)                                  // 锁住变量比锁住UI控件容易
                        {
                            onlineIP.Add(tmpIP + "未在线");
                            ShowIPScanResult uplsB = new ShowIPScanResult(Update_lsB_LiveHost);// 子线程一般不能直接修改UI,所以用这块委托(放外面可能会乱了)
                            this.Invoke(uplsB);
                        }
                    }
                    scanedIPCount ++;
                    ShowIPScanResult upproBar = new ShowIPScanResult(Update_proBar_IPscan);
                    this.Invoke(upproBar);
                    goto ScanLeftIP;                                    // 死循环等待所有IP被扫描子完了,否则继续扫
                }
                else
                {
                }            }
                
            }
      

  13.   


    程序本来的意图是通过 多线程 并行处理 needScanIP,提高效率。 可现在每个线程 通过 lock 独占共享资源,没有达到 并行的效果吧?