多线程

来源:互联网 发布:linux查看物理cpu个数 编辑:程序博客网 时间:2024/06/05 09:22


多线程问题

对于一个winform程序,当我们在抓取图片的时候,如果数量过多,当程序运行的时候,此程序窗口不能拖动也不能点击此程序窗口中的其他按钮。为了解决以上问题,我们可以用多线程。

1、手动创建一个线程,利用Thread类,Thread mythread=new Thread();有四个重载函数,我们可以用第二个参数,ThreadStart类型的实例, System.Threading.ThreadStart 委托,它表示此线程开始执行时要调用的方法。而这个委托所对应的方法是没有参数和返回值的方法。

所以我们可以将下载图片的运行代码放在一个没有参数和返回值的方法中,再通过手动创建线程调用。

例如:



 private void button1_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(DownLoadImg);
            //不是真正的启动这个线程,而是告诉cpu,这个线程已经准备就绪,只要您有时间,就可以来调用了
            mythread.Start();
     
        }
        private void DownLoadImg()
        {
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;

            string str = client.DownloadString(this.textBox1.Text);
            MatchCollection mc = Regex.Matches(str, @"正则表达式
");
            int totalcount = mc.Count;
            int count = 0;
            foreach (Match item in mc)
            {
                client.DownloadFile(item.Value, @"d:\myimages\" + Path.GetFileName(item.Value));
               
                //progressBar1在窗体上,而创建窗体的是前台线程,下载图片的代码存在于后台线程中,两个线程不能这样简单的直接通讯,需要通过委托来做。委托就是预留的接口。
                //count++;
               
                //this.progressBar1.Value = Convert.ToInt32(Math.Floor((Convert.ToDouble(count) / Convert.ToDouble(totalcount)) * 100));

            }
           
        }

这样我们在下载图片的时候就可以拖动运行的窗口,或者点击窗口上的其他按钮。

但是:我们无法访问到主线程上的控件,例如progressBar1(进度条)。不能跨线程 直接访问控件。

为了解决以上问题,我们可以用委托(不严谨)。在winform程序中可以在构造函数中进行属性设置,可以解决问题。

例如:

public MainForm()
        {
            //this.textBox1.Text = "ddd";
            InitializeComponent();//绘制窗体上的控件
           
            //设置一个值,设置是否检查允许跨越线程的调用,默认值true,就是说检查
            this.Text = Thread.CurrentThread.ManagedThreadId.ToString();
            //这只是不得已的一种解决方案----掩耳盗铃,自欺欺人
            //Control.CheckForIllegalCrossThreadCalls = false;
        }

用委托实现将下载的个数显示在TextBox上,格式:当前下载第x个,
在.NET中,所有的控件都是从System.Windows.Forms.Control类派生,Control类提供了一个Invoke()方法,用 于在创建控件的线程中访问线程.它的定义如下:
public Object Invoke(Delegate method);
它的参数为一个委托,代表创建控件的线程中要执行的方法.
可以利用这个方法来实现这个功能.
所以我们要修改 DownLoadImg()方法

 int count = 0;
 private void DownLoadImg()
        {
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;

            string str = client.DownloadString(this.textBox1.Text);
            MatchCollection mc = Regex.Matches(str, @"正则表达式
“);
            int totalcount = mc.Count;
          
            foreach (Match item in mc)
            {
                client.DownloadFile(item.Value, @"d:\myimages\" + Path.GetFileName(item.Value));
               
                //progressBar1在窗体上,而创建窗体的是前台线程,下载图片的代码存在于后台线程中,两个线程不能这样简单的直接通讯,需要通过委托来做。委托就是预留的接口。
                count++;
               

.NET中自定义了一个没有参数,没有返回值的一个委托,即Action,所以我们可以直接用这个委托
               Action myaction1 = new Action(TiShi);
                this.BeginInvoke(myaction1);

            }
           
        }

 private void TiShi()
        {
            this.textBox2.Text = "当前下载已完成"+count+"";
        }


我们也可以不用自定义的委托,我们可以手动定义委托。

首先定义一个委托:
public delegate void setLabelTextDelegate();//定义一个setLabelTextDelegate()的委托
在定义一个委托变量:在public partial class Form1 : Form
    {
        private setLabelTextDelegate setLabelText;//第一变量
        public Form1()
        {
            InitializeComponent();
        }
}


在DownLoadImg()方法中,将后两句改为:
 setLabelText = TiShi;
                this.BeginInvoke(setLabelText);
即可。


如果我们不将count定义在方法的外部,那我们就需要一个参数方法,即我们就要定义一个参数委托。
public delegate void setLabelTextDelegate(int aa);//
    public partial class Form1 : Form
    {
        private setLabelTextDelegate setLabelText;
        public Form1()
        {
            InitializeComponent();
        }
}

修改对应的方法:
 private void TiShi(int aa)
        {
            this.textBox2.Text = "当前下载已完成"+aa+"";
        }

对Invoke()这个方法是有重载的,它的定义如下:
public Object Invoke(Delegate method,param Object [] args);
第二个参数是一个object的数组,就意味着,可以把需要传递的参数放到这个数组里面来进行传递

那么DownLoadImg()方法应该为:

 private void DownLoadImg()
        {
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;

            string str = client.DownloadString(this.textBox1.Text);
            MatchCollection mc = Regex.Matches(str, @“正则表达式
");
            int totalcount = mc.Count;
            int count = 0;
            foreach (Match item in mc)
            {
                client.DownloadFile(item.Value, @"d:\myimages\" + Path.GetFileName(item.Value));

                //progressBar1在窗体上,而创建窗体的是前台线程,下载图片的代码存在于后台线程中,两个线程不能这样简单的直接通讯,需要通过委托来做。委托就是预留的接口。
                count++;
                setLabelText = TiShi;
                this.TextBox2.BeginInvoke(setLabelText,count);

            }
        }

TextBox2可加可不加。


0 0