多线程、委托、线程同步举例及解析!

时间:2022-12-17 10:45:38

多线程、委托、线程同步举例及解析!(里面部分内容有问题,敬请讨论…………)
(其截图和最后的exe文件可到(http://download.csdn.net/user/shuanghusun)下载)
本例子采用单线程,源代码如下;如果在网络资源不是很好的情况下,执行效率可能会很低,故可以采用多线程!但在该例子中,有几点需要注意:
一、使用委托。
C#中的控件执行时,均是主线程在执行,而自己创建的线程称为辅助线程。当在辅助线程中调用C#控件时,这时会出现异常,为解决这个问题,.net采用了委托机制。比如例子中当在
辅助线程中访问richTextBox1时使用了委托。
---------------------------------------
在该例子中,当创建线程后,然后.start(),但并不意味着线程已经启动了,他们只是处于等
待状态,如果cpu将时间片足够多的分配给某个线程,则该线程才启动。
在该例子中,为了计算线程结束时间,故在线程循环体外,需要进一步判断一下这几个线程是
不是还“活着”,即isAlive属性,确定这几个线程都不存在时,即isAlive飞属性为false时,
这时再计算一下时间当前时间, DateTime time2 = DateTime.Now; 然后将刚执行时的时间与
time2相减就是线程执行时间了。
这种想法看似正确,但当执行时会出现假死状态,采用单步调试查错发现,程序一直处在判断
isAlive的死循环。原因就是:假如有一个线程处于等待状态,而当另一个线程调用richTextBox1
时需要使用委托,当第二次判断委托时,会让主线程调用C#控件,而如果与此同时cpu将时间片分
给了某一线程后,该线程然后判断isAlive,如果分给该线程的时间不够,循环继续,(主线程调用)
这时,主线程调用委托,而此时,主线程又不断在执行循环……,故会造成界面卡死。
因此解决的办法,通常有2种,一是采用lock同步,二是再创建一个线程,将死循环放在一个线程中。
二、使用线程同步。使用同步时,锁定的对象应该是私有的object类型的。
三、如果采用创建线程的方法,可以构造一个方法,然后遍历每一个已经创建的线程,判断isAlive属性。
四、之后计算线程全部启动后的时间,相减就OK了!记着声明一个全局变量,赋于ipCount!
--------
当然,除了上述二种方法外,还可以采用第三种方法,调用InVokeRequire方法,具体如何实现大家可以
再讨论。
本例子中的部分代码…………

方法三:


//创建一个线程数组
            scanThreads = new Thread[ipCount];
            for (int i = 0; i < ipCount; i++)
            {
                //定义Scan实例
                Scan scanObj = new Scan();

                //传递ip地址
                scanObj.strip = subIP + "." + (start + i).ToString();
                scanObj.d = AddStatusInfoToListBox;
                //初始化线程实例
                scanThreads[i] = new Thread(scanObj.CheckComputer);
//计算线程启动时间时创建线程所调用的方法
while (true)
            {
                OverNum = 0;
                foreach (Thread item in scanThreads)
                {
                    if (!item.IsAlive)
                    {
                        OverNum++;
                    }
                }
                //全部结束
                if (OverNum == scanThreads.Length)
                {
                    DateTime dt = DateTime.Now;
                    TimeSpan sp = new TimeSpan(dt.Ticks - start.Ticks);
                    MessageBox.Show(sp.Milliseconds.ToString());
                    break;
                }
            }
方法二:
 lock (str)
                {
                    Form1.runum--;
                }
while (Form1.runum > 0)
            {
               
                 ;
            }
            DateTime dt = DateTime.Now;
            TimeSpan sp = new TimeSpan(dt.Ticks-time1.Ticks );
            MessageBox.Show(sp.Milliseconds.ToString());
如果需要详细代码,可与本人联系!!


////采用单线程的完整代码如下:


namespace ScanComputer
{public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    public void AddStatusInfoToListBox(string strIP, string strHostName)
    {
       
            listBoxStatus.Items.Add(string.Format("IP地址:{0}----域名:{1}", strIP, strHostName));
      
    }
    private void buttonScan_Click(object sender, EventArgs e)
    {
        DateTime time1 = DateTime.Now;
        listBoxStatus.Items.Clear();
        //获取IP地址范围
        string subIP = numericUpDown1.Value.ToString() + "." + numericUpDown2.Value.ToString() + "." + numericUpDown3.Value.ToString();
        int start = Convert.ToInt32(numericUpDown4.Value);
        int end = Convert.ToInt32(numericUpDown5.Value);
        //判断合法性
        if (end < start)
        {
            MessageBox.Show("IP地址区间不对!请确认后重新输入!");
            return;
        }
        //获取ip地址的个数
        int ipCount = end - start + 1;
        for (int i = 0; i < ipCount; i++)
        {
            string strip=subIP + "." + (start+i).ToString();
            IPAddress ipAddress = IPAddress.Parse(strip);
            IPHostEntry hostEntry = Dns.GetHostEntry(ipAddress);
            string strHostName = hostEntry.HostName.ToString();
            AddStatusInfoToListBox(strip, strHostName);
        }
        DateTime time2 = DateTime.Now;
        TimeSpan sub = time2 - time1;
        MessageBox.Show(sub.ToString());
    }
}
}