视频一:线程的介绍及线程的基本语法
1.线程的创建
Thread th = new Thread(Func);//创建线程
th.Start();//启动线程
private void Func()//线程执行的方法
{///填写方法
}
2.学习线程最经典的错误
2.1线程间操作无效:从不是创建控件“label1”的线程访问它。
解决方案:忽略异常,跨线程操作。 Control.CheckForIllegalCrossThreadCalls = false;//忽略跨线程间的调用,不推荐大家使用,它可能会引发一些未知的异常。
2.2创建窗口句柄时出错
引发原因:窗口被结束,但是线程还未结束。虽然看着窗体已经结束,但是任务管理器中一样可以看到进程依然存在在运行。 UI关闭后,没有通知后台线程结束,主线程未完全退出,因为只要有一条子线程还在运行,那么它(子线程)将阻塞主线程关闭。
解决方案:th.IsBackground = true;//当前线程为后台线程,则会完全退出程序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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();//启用线程 } } }
视频二:线程的高级写法接受任意参数
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) {}//锁
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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(); } } } }
4.提供类的好处:帮助理解他人是如何处理线程
两种情况:固定线程数,不固定任务数
固定任务数,自动计算线程数
缺点:无法重复利用线程
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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]); } } } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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); } } } }
视频教程出自:http://www.xuanjics.com/thread-67-1-1.html
玄机论坛的地址:www.xuanjics.com 原创作者:君临