程序是扫描局域网里的主机:    public delegate void OnUiControl();
    private void button1_Click(object sender, EventArgs e)
        {
           Thread thScan = new Thread(new ThreadStart(DoControl));                 
             thScan.IsBackground = true;
            thScan.Start();
        }
        private void DoControl()
        {
            OnUiControl uicontrol = this.ScanTarget;
            if (this.InvokeRequired)
            {
                this.Invoke(uicontrol);
            }
        }
       
        private void ScanTarget()
        {
            string strIPAddress = "172.30.81."; //ip段
            int nStrat = Int32.Parse("2");   //开始扫描地址
            int nEnd = Int32.Parse("50");  //终止扫描地址
            //开始扫描(耗时操作)
            for (int i = nStrat; i <= nEnd; i++)
            {
              string strScanIPAdd = strIPAddress + i.ToString();
              IPAddress myScanIP = IPAddress.Parse(strScanIPAdd); //转换成IP地址  
                try
                 { 
                   //当执行下面这个操作时候比较耗时
                    IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd); 
                     string strHostName = myScanHost.HostName;
                    richTextBox1.AppendText(strHostName + "\r");
                    Application.DoEvents();
            
                }
                catch (Exception error)
                {
                    MessageBox.Show(error.Message);
                }
               }
        }
上面是原程序,为什么使用了多线程后界面还会卡死呢?求解

解决方案 »

  1.   


    private Action<string> _reportIP;
            private void button1_Click(object sender, EventArgs e)       
            {
                //回调处理
                this._reportIP = ip => this.richTextBox1.AppendText(ip + "\r");
                Thread thScan = new Thread(new ThreadStart(ScanTarget));  
                thScan.IsBackground = true;            
                thScan.Start();        
            }                   
            
            private void ScanTarget()   
            {           
                string strIPAddress = "172.30.81."; //ip段  
                int nStrat = Int32.Parse("2");   //开始扫描地址            
                int nEnd = Int32.Parse("50");  //终止扫描地址     
                //开始扫描(耗时操作)           
                for (int i = nStrat; i <= nEnd; i++)            
                {              
                    string strScanIPAdd = strIPAddress + i.ToString();
                    IPAddress myScanIP = IPAddress.Parse(strScanIPAdd);    //转换成IP地址
                    try                 
                    {                    
                        //当执行下面这个操作时候比较耗时 
                        IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd);                    
                        this._reportIP(myScanHost.HostName);                   
                    }                
                    catch (Exception error)
                    {                   
                        MessageBox.Show(error.Message); 
                    }             
                }      
            }
      

  2.   


    你虽然写了一行代码进行所谓“使用多线程”,可是这个线程中立刻执行this.Invoke(uicontrol);这种多线程有什么意义呢?
      

  3.   

    http://download.csdn.net/detail/caozhy/4832657参考这个例子。
      

  4.   

    this.Invoke(uicontrol)是为了解决跨线程访问UI控件报错的问题,希望sp1234指导,我只是一个菜鸟
      

  5.   

    this.Invoke(uicontrol) 就是阻塞自己,直到主线程处理完这个uiconttol。因此你的目地不但没有达到,反而比不用线程还要更糟。
      

  6.   

    那该怎么解决呢,如果不这样线程会出现"线程间间操作无效",我网上查了线程间操作的大都是用的this.Invoke()方法,或许我这样操作不对,给点思路也好
      

  7.   


    private void DoControl()        {            OnUiControl uicontrol = this.ScanTarget;            if (this.InvokeRequired)            {                this.Invoke(uicontrol);            }        }this.Invoke方法会使用主线程去操作的。
    而这是应该用后台线程去操作耗时的东东。
      

  8.   


    刚测了下,不会卡界面,是不是其他地方引起的?对界面的更新,都放那个委托里面
    //回调处理
    private Action<string> _reportIP;
    private int nStrat = 2, nEnd = 50;  //扫描地址范围
    //----上面是成员变量,放在方法外----      private void button1_Click(object sender, EventArgs e)       
          {
                //回调处理可移到Form_Load中,如果其他的Form要用到,最好封装到事件中去
                this._reportIP = ip =>
                {
                    this.richTextBox1.AppendText(ip + "\r");
                    //假设界面上还有一个进度条
                    int curIP = int.Parse(ip.Split(".").Last());
                    this.progessBar1.Value = (curIP - nStrat) / (nEnd - nStrat) * 100;
                    //继续加更新界面的代码...
                };
                Thread thScan = new Thread(new ThreadStart(ScanTarget));  
                thScan.IsBackground = true;            
                thScan.Start();
           }  
      

  9.   

    我又试了下,发现如果把Main函数上的[STAThread]注释掉,就会出现LZ所说的问题,但是其实这个标记是WinForm默认的,表示以单线程方式与COM组件之间进行通信。它并不会影响到你在Form里使用多线程技术,除非你用到了ActiveX或者第三方的软件COM
      

  10.   

    用的是VS2010的3.5的,改成4.0的就报错了,下面这样可以public partial class FrmTest : Form
        {
            private Action<IPHostEntry> _reportIP;
            private int nStrat = 100, nEnd = 150;  //扫描地址范围
            private bool _asyCancellation = false;                public FrmTest()
            {
                InitializeComponent();            
            }        private void ScanTarget()
            {
                string strIPAddress = "192.168.0."; //ip段
                //开始扫描(耗时操作)           
                for (int i = nStrat; i <= nEnd; i++)
                {
                    if (this._asyCancellation) return;
                    string strScanIPAdd = strIPAddress + i.ToString();
                    IPAddress myScanIP = IPAddress.Parse(strScanIPAdd);    //转换成IP地址
                    try
                    {
                        //当执行下面这个操作时候比较耗时 
                        IPHostEntry myScanHost = Dns.Resolve(strScanIPAdd);
                        if (this.InvokeRequired)
                        {
                            this.Invoke(this._reportIP, myScanHost);
                        }
                        else
                        {
                            this._reportIP(myScanHost);
                        }
                    }
                    catch (Exception error)
                    {
                        MessageBox.Show(error.Message);
                    }
                }
            }        private void OnResolvedCallback(IPHostEntry ip)
            {
                this.richTextBox1.AppendText(ip.HostName + "\r");
                //假设界面上还有一个进度条            
                var curIP = (int)ip.AddressList[0].GetAddressBytes().Last();
                var rate = (curIP - nStrat) / (double)(nEnd - nStrat);
                this.progressBar1.Value = Convert.ToInt32(rate * 100);            
            }        private void btnOK_Click(object sender, EventArgs e)
            {
                if (!this._asyCancellation)
                {
                    if (this._reportIP == null) this._reportIP = this.OnResolvedCallback;
                    this.progressBar1.Value = this.progressBar1.Minimum;
                    Thread thScan = new Thread(new ThreadStart(ScanTarget));
                    thScan.IsBackground = true;
                    thScan.Start();
                }
            }        private void btnCancel_Click(object sender, EventArgs e)
            {
                this._asyCancellation = true;
                this.progressBar1.Value = this.progressBar1.Maximum;
            }
        }
    直接用BackgroundWoker省事多了