番外篇之多线程

 

 

 

视频一:线程的介绍及线程的基本语法

           1.线程的创建
               Thread th = new Thread(Func);//创建线程
               th.Start();//启动线程
               private void Func()//线程执行的方法
               {///填写方法
               }

            2.学习线程最经典的错误

                2.1线程间操作无效:从不是创建控件“label1”的线程访问它。

                     解决方案:忽略异常,跨线程操作。 Control.CheckForIllegalCrossThreadCalls = false;//忽略跨线程间的调用,不推荐大家使用,它可能会引发一些未知的异常。

                 2.2创建窗口句柄时出错

                      引发原因:窗口被结束,但是线程还未结束。虽然看着窗体已经结束,但是任务管理器中一样可以看到进程依然存在在运行。 UI关闭后,没有通知后台线程结束,主线程未完全退出,因为只要有一条子线程还在运行,那么它(子线程)将阻塞主线程关闭。

                     解决方案:th.IsBackground = true;//当前线程为后台线程,则会完全退出程序                

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace 番外篇之多线程
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;//忽略跨线程间的调用,不推荐大家使用,它可能会引发一些未知的异常
        }

        private void Form1_Load(object sender, EventArgs e)
        {
           
        }
        private void Func()//线程执行的方法
        {
            for (int i = 0; i < 100000; i++)
            {
                label1.Text = i.ToString();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(Func);//创建线程
            th.IsBackground = true;//当前线程为后台线程
            th.Start();//启用线程
        }
    }
}
View Code

 

 

 

视频二:线程的高级写法接受任意参数

           1.参数的传递,object类型的方式,而且仅能一个参数

              private void GetInfo(object strinfo)
            {
            MessageBox.Show(strinfo.ToString());
             }
            private void button1_Click(object sender, EventArgs e)
            {
            string strinfo = "Andrew";
            Thread thread = new Thread(GetInfo);
            thread.Start((object)strinfo);
           }

           2.参数的传递,非object类型的方式,且可以多个参数

               private void GetInfo(object strinfo,string str)
              {
              MessageBox.Show(strinfo.ToString());
              }
             private void button1_Click(object sender, EventArgs e)
             {
              string strinfo = "Andrew";
              Thread thread = new Thread(new ThreadStart(delegate { GetInfo((object)strinfo, strinfo); }));
              thread.Start();
             }

          3.使用线程池,缺点:线程池是不可以控制的。

               private void GetInfo(object strinfo,string str)
            {
            MessageBox.Show(strinfo.ToString());
            }
            private void button1_Click(object sender, EventArgs e)
            {
            string strinfo = "Andrew";
            //Thread thread = new Thread(GetInfo);
            //thread.Start((object)strinfo);
            //Thread thread = new Thread(new ThreadStart(delegate { GetInfo((object)strinfo, strinfo); }));
            //thread.Start();
            ThreadPool.QueueUserWorkItem(p => { GetInfo(strinfo, strinfo); });
            ThreadPool.QueueUserWorkItem(new WaitCallback(delegate{ GetInfo(strinfo, strinfo); }));
           }

            4.Thread.Sleep(100);//睡眠,挂起 参数(int)单位毫秒,是全局有效。

 

 

 视频三:稍微高级点的线程控制以及多线程常用的场景

            1.线程暂停及恢复

              1.1 th.Suspend();////挂起线程

                     if (th.ThreadState != ThreadState.Suspended)  //本来判断是否为后台线程的,但是由于线程处理会有一个时间(就会造成线程无法停止),所以直接判断是不是被挂起
                     {
                    //挂起后台线程
                    th.Suspend();
                     }

              1.2  th.Resume();////继续挂起的线程

                      if (th != null && th.ThreadState!= ThreadState.Running) //判断是否为后台线程,是否被挂起
                      {
                      th.Resume(); //继续线程
                      }

               1.3  th.TreadState////线程的状态枚举

           2.应用场景 Post程序,需要输入验证码

              先开启线程,来执行get请求,得熬验证码图像,挂起这个线程,等待验证码的输入        

           3.lock(this) {}//锁

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Thread_Dom
{
    public partial class Form1 : Form
    {
        private AutoResetEvent m_autoEvent;
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false; //跨线程访问From控件中的Lab,最好使用委托来在UI显示.最好不用这种方式,容易造成线程间安全问题.
        }

        private void Form1_Load(object sender, EventArgs e)
        { 
        } 
        Thread th;
        private void btnOk_Click(object sender, EventArgs e)
        {
            btnOk.Enabled = false;
            #region 同步后台线程间挂起恢复 | 启动线程 
            //同步线程
            th = new Thread(Funcs);
            th.IsBackground = true;
            th.Start(); 
            #endregion 
            
        }
        private void Funcs(object o)
        {
            
            for (int i = 0; i < 99999999; i++)
            {
                Thread.Sleep(100);
                labnum.Text = i.ToString();

            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            btnOk.Enabled = true;
            #region 同步后台线程间挂起恢复 | 暂停线程
         
            
           // MessageBox.Show("暂停线程..");
            if (th.ThreadState != ThreadState.Suspended)  //本来判断是否为后台线程的,但是由于线程处理会有一个时间(就会造成线程无法停止),所以直接判断是不是被挂起
            {
                //挂起后台线程
                th.Suspend();
            }
            
            #endregion
          
        }

        private void button2_Click(object sender, EventArgs e)
        {
            button1.Enabled = true;
            #region 同步后台线程间挂起恢复 | 恢复线程
           
            //MessageBox.Show("恢复线程..");    //线程间调用messagebox会直接阻塞线程,所以看起来不同步,注释掉就ok
            
             
            if (th != null && th.ThreadState!= ThreadState.Running) //判断是否为后台线程,是否被挂起
            {
                th.Resume(); //继续线程
            }
            #endregion
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
             
        }
        object o = new object();
        bool b = false;
        private void Post()
        {
            for (int i = 0; i <10; i++)
            {
                //5出现验证码
                if (i == 5)
                {
                    while (true)
                    {
                        if (b!=false)
                        {
                            continue;
                        }
                    }
                   // thread.Suspend();
                    //接收验证码的输入.
                    string vcode = txtVcode.Text;
                    //.....
                }
                
            }
        }
        Thread thread;
        private void button3_Click(object sender, EventArgs e)
        {
            thread = new Thread(new ThreadStart(delegate
            {
                Post();
            }));
            thread.Start();
        }

        private void txtVcode_TextChanged(object sender, EventArgs e)
        {
            if (txtVcode.Text.Length == 4)
            { 
                thread.Resume();
            }
        }

        private void txtVcode_KeyPress(object sender, KeyPressEventArgs e)
        {
             if(e.KeyChar==(char)13)
             {
                 thread.Resume();
             }
        }

        
    }
}
View Code

           4.提供类的好处:帮助理解他人是如何处理线程

              两种情况:固定线程数,不固定任务数

                            固定任务数,自动计算线程数

              缺点:无法重复利用线程

             

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ThreadCallBack
{
    /// <summary>
    /// 线程任务
    /// </summary>
    public class ThreadTask
    {
        /// <summary>
        /// 分页多线程
        /// </summary>
        /// <param name="ThreadIndex">线程序号</param>
        /// <param name="ExeCount">一条线程需要执行程序的个数</param>
        /// <param name="ThreadCount">线程总数</param>
        /// <param name="list"></param>
        public void ThreadRun(int ThreadIndex, int ExeCount, int ThreadCount, List<string> list)
        {

            if (ThreadIndex < ThreadCount)
            {
                for (int i = (ThreadIndex - 1) * ExeCount; i < (ThreadIndex) * ExeCount; i++)
                {
                    Console.WriteLine("当前线程:     " + Thread.CurrentThread.Name + "           执行任务I--" + list[i]);

                }
            }
            else
            {
                for (int i = (ThreadIndex - 1) * ExeCount; i < list.Count; i++)
                {
                    Console.WriteLine("当前线程:     " + Thread.CurrentThread.Name + "          执行任务I --" + list[i]);
                }

            }

        }
    }
}
View Code

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadCallBack
{
    delegate int GetRes(int i, int j);
    public partial class Form1 : Form
    {
        GetRes getres;
        public Form1()
        {
            //懒得写委托了.
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
        }
        private int sum(int i, int j)
        {
            return i + j;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            AsyncCallback async = new AsyncCallback(GetRes4Async);
            getres.BeginInvoke(1, 2, async, null);

        }
        private void GetRes4Async(IAsyncResult iasync)
        {
            if (iasync.IsCompleted)
            {
                //完成
                int res = getres.EndInvoke(iasync);
                resLab.Text = res.ToString(); 
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            getres = new GetRes(sum);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            List<string> slist = new List<string>();
            for (int i = 0; i < 139999; i++)
            {
                slist.Add(i.ToString());
            }
             
            //分页定律    
            //ThreadIndex 第几页   第几条线程
            decimal ExeCount = 99999; //每页显示多少个    需要执行程序的个数  分几次执行,一次处理多少条.

            int ThreadCount = int.Parse(Math.Ceiling((decimal)(slist.Count / ExeCount)).ToString()); //计算线程总数
            Thread[] thd = new Thread[ThreadCount];
            for (int ThreadIndex = 1; ThreadIndex < ThreadCount + 1; ThreadIndex++)
            {
                int thIndex = ThreadIndex - 1;
                ThreadTask task = new ThreadTask();
                thd[thIndex] = new Thread(new ThreadStart(delegate
                {
                    task.ThreadRun(ThreadIndex, int.Parse(ExeCount.ToString()), ThreadCount, slist);

                }));
                thd[thIndex].Name = thIndex.ToString() + "------>Name";
                thd[thIndex].Start();
                Thread.Sleep(10);
                
            }

        }

        private void button3_Click(object sender, EventArgs e)
        {
            int threadCount = (int)ThreadupDown.Value; //线程数
            List<string> slist = new List<string>();
            for (int i = 0; i < 139999; i++)
            {
                slist.Add(i.ToString());
            }
            Thread[] thd = new Thread[threadCount];
            //任务数/线程数 = 单条线程执行的任务数
            int ExeCount = int.Parse(Math.Ceiling(((decimal)slist.Count / threadCount)).ToString());
            //从1开始的目的就是执行第一批(比较好计算)..下面继续-1,就是线程下标..这段代码写的比较2..
            for (int ThreadIndex = 1; ThreadIndex < threadCount + 1; ThreadIndex++)
            {
                int thIndex = ThreadIndex - 1;
                ThreadTask task = new ThreadTask();
                thd[thIndex] = new Thread(new ThreadStart(delegate
                {
                    task.ThreadRun(ThreadIndex, ExeCount, threadCount, slist); 
                }));
                thd[thIndex].Name = thIndex.ToString() + "------>Name";
                thd[thIndex].Start();
                Thread.Sleep(10); 
            }

        }

    }
}
View Code

 

 

 

   

 

 

 

 

 

视频教程出自:http://www.xuanjics.com/thread-67-1-1.html

                    玄机论坛的地址:www.xuanjics.com  原创作者:君临

                    QQ交流群:16885911  

                

posted @ 2014-10-27 09:31  阳光少年1712  阅读(208)  评论(0编辑  收藏  举报