c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)

总结:视频中对于多线程讲的非常透彻,从线程基础概念—>.net不同版本出现的线程方法—>多线程常出现问题—>双色球项目实践,每个知识点都有代码实操,受益匪浅。附上学习笔记和实操代码。
视频

目录

  • 一、线程、进程概念及优缺点
  • 二、四种异步等待方式
    • 1.异步控制等待-callback回调
    • 2.异步控制等待-asyncResult.IsCompleted
    • 3.异步控制等待WaitOne()-信号量
    • 4.异步控制等待endinvoke-拿到异步函数的返回值
    • 5.视频第1节课代码
  • 三、.net1.0基础版的thread对象
    • 1.线程启动
    • 2.thread.join()\thread.sleep()\thread.IsBackfround
  • 四、net 2.0 threadpool
    • 1.线程启动、设置线程池最大线程数
    • 2.manualResetEvent.WaitOne()异步控制等待
    • 3.手写异步回调函数
    • 4.带返回值的委托异步调用(法语结构待学习)
  • 五、.net3.0 task
    • 1.task线程启动
    • 2.waitall、waitany都会卡主线程卡界面
    • 3.task.whenall.continuewith()
    • 4.taskfactory.continuewith()
    • 5.设计最多只有11个线程在工作
    • 6.taskfactory检测到哪个线程结束后,返回线程标识
    • 7.task多次嵌套实现不卡主线程
    • 8.两个waitall按顺序执行
    • 9.thread.sleep()卡线程 task.delay()不卡线程
    • 10.task线程完成标识
  • 六、.net4.5 parallel
    • 1.parallel启动多线程
    • 2.parallel线程停止
  • 七、threadcore
    • 1.异常处理
    • 2.线程取消
    • 3.多线程临时变量
    • 4.线程安全lock(lock锁的是引用)
      • 4.1线程安全问题
      • 4.2线程共有变量存在线程安全问题
      • 4.3lock锁原理
  • 八、.net.0 await/async
    • 1.await原理
      • 1.1小代码测试原理
    • 2.带与不带返回值的async方法
      • 2.1只有asynic
      • 2.2asynic\await成对出现
      • 2.3t.Wait()与await t区别
      • 2.4await反编译-相当于状态机
    • 3.此知识点代码
  • 九、双色球项目
    • 1.代码
  • 十、知识点代码汇总

一、线程、进程概念及优缺点

线程:程序执行的最小单位,任何操作都是由线程完成的,使用同步时,资源一直被此线程占用,所以其他界面干不了,会出现卡界面的现象。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
1启动不可控制、2结束不可控
在这里插入图片描述
主线程代码
一个耗时(i++)、耗资源(thread.sleep)的方法
在这里插入图片描述

二、四种异步等待方式

1.异步控制等待-callback回调

action执行完将asyncResult、"nimen"当成参数传给callback
在这里插入图片描述

2.异步控制等待-asyncResult.IsCompleted

在这里插入图片描述

3.异步控制等待WaitOne()-信号量

在这里插入图片描述

4.异步控制等待endinvoke-拿到异步函数的返回值

在这里插入图片描述
在这里插入图片描述

5.视频第1节课代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace multithread
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){Console.WriteLine($"[------------主线程start: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");/*1调用委托{Action<string> action = this.dosomething;action.Invoke("AA");//同步调用委托action("BB");//同步调用委托action.BeginInvoke("cc", null, null);//异步调用委托}/*2异步-不可控{Action<string> action = this.dosomething;for (int i = 0; i < 5; i++){string name = string.Format($"btn_click_{i}");action.BeginInvoke(name, null, null);//异步调用委托}}*//*3.异步不可控{ Action<string> action = this.dosomething;action.BeginInvoke("cc", null, null);Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");}*//*4.异步等待1-回调{Action<string> action = this.dosomething;AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));//简单写法AsyncCallback callback1 = i => Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");action.BeginInvoke("cc", callback, null);}*//*5.异步等待1-回调解析(action执行完将asyncResult、"nimen"当成参数传给callback)-不卡界面{Action<string> action = this.dosomething;IAsyncResult asyncResult = null;AsyncCallback callback = i =>{Console.WriteLine(object.ReferenceEquals(asyncResult , i));Console.WriteLine(i.AsyncState);Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");};asyncResult = action.BeginInvoke("cc", callback, "nimen");}*//*6.异步等待2 asyncResult.IsCompleted-回调解析-while函数卡界面{Action<string> action = this.dosomething;IAsyncResult asyncResult = null;AsyncCallback callback = i =>{Console.WriteLine(object.ReferenceEquals(asyncResult, i));Console.WriteLine(i.AsyncState);Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");};asyncResult = action.BeginInvoke("cc", callback, "nimen");int a = 0;while (!asyncResult.IsCompleted){if (a < 10){Console.WriteLine($"文件上传{a++ * 10}%..");Console.WriteLine($"线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");}else{Console.WriteLine($"文件上传99.9%..");}Thread.Sleep(200);}}*//*7.异步等待3-WaitOne()-信号量3{Action<string> action = this.dosomething;IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);Console.WriteLine("dosomething");Console.WriteLine("dosomething");asyncResult.AsyncWaitHandle.WaitOne();//等待异步任务完成后,才打印计算完成asyncResult.AsyncWaitHandle.WaitOne(2000);//限时等待Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");}*//*.8异步等待4endinvoke-拿到委托函数的返回值{Action<string> action = this.dosomething;Func<int> func = () =>{Thread.Sleep(2000);return DateTime.Now.Day;};Console.WriteLine($"func.Invoke()={ func.Invoke()}");IAsyncResult asyncResult=func.BeginInvoke(r =>{Console.WriteLine(r.AsyncState);}, "nimen");Console.WriteLine($"func.EndInvoke={ func.EndInvoke(asyncResult)}");Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");}*/Console.WriteLine($"[------------主线程end: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");}private void dosomething(string name){Console.WriteLine($"[****Dosomething {name} start: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");long result = 0;for(int i =0; i < 10000000; i++){result += i;}Thread.Sleep(2000);Console.WriteLine($"[****Dosomething {name} end: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}{result}*******]");}}
}

三、.net1.0基础版的thread对象

1.线程启动

 {//Action<string> action = this.dosomething;//IAsyncResult asyncResult = action.BeginInvoke("cc", null, null);//Action action1 =()=> this.dosomething("CC");//1.线程启动 thread.Start();ThreadStart threadStart = () => this.dosomething("cc");Thread thread = new Thread(threadStart);thread.Start();//2.线等待程thread.Join();thread.Join(500);//卡主线程Console.WriteLine($"等待500ms");thread.Join();while (thread.ThreadState != ThreadState.Stopped){Thread.Sleep(100);//cpu时间片交出去干其他的事,但是内存还是占用}

在这里插入图片描述

2.thread.join()\thread.sleep()\thread.IsBackfround

thread.join(500),是其他人线程等他500ms,此时有两个线程在工程, 一个在等待500ms,一个是自己在运行
thread.sleep(500),是自己线程自己将cpu时间片交出去干其他的事,但是内存还是占用,休眠500ms
前台线程,当软件闪退时,会吐出日志
在这里插入图片描述

四、net 2.0 threadpool

在这里插入图片描述

1.线程启动、设置线程池最大线程数

在这里插入图片描述
在这里插入图片描述

2.manualResetEvent.WaitOne()异步控制等待

            {ManualResetEvent manualResetEvent = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(t => {this.dosomething("cc");manualResetEvent.Set();});//接收一个没有返回值的委托manualResetEvent.WaitOne();Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");}

在这里插入图片描述
waitone()风险,无线程可用会卡住
在这里插入图片描述

3.手写异步回调函数

在这里插入图片描述

4.带返回值的委托异步调用(法语结构待学习)

在这里插入图片描述

五、.net3.0 task

1.task线程启动

在这里插入图片描述

2.waitall、waitany都会卡主线程卡界面

在这里插入图片描述
在这里插入图片描述
waitall、waitany应用场景
在这里插入图片描述

3.task.whenall.continuewith()

首先task.whenall不卡主界面,快快的结束了btn_task_click是主线程任务
其次continuewith() ,当tasklist中线程执行后并满足条件时(all\any),直接顺序执行下面的委托,类似回调如“得意的笑”
在这里插入图片描述
在这里插入图片描述

4.taskfactory.continuewith()

在这里插入图片描述
在这里插入图片描述

5.设计最多只有11个线程在工作

在这里插入图片描述

6.taskfactory检测到哪个线程结束后,返回线程标识

在这里插入图片描述
在这里插入图片描述

7.task多次嵌套实现不卡主线程

在这里插入图片描述
在这里插入图片描述

8.两个waitall按顺序执行

如果有两个waitall需要执行但他们在不同线程中,但是又要保证这两次waitall的顺序,解决办法,将第一个waitall加到tasklist中,然后让第二个task的waitall来判断
在这里插入图片描述

9.thread.sleep()卡线程 task.delay()不卡线程

在这里插入图片描述
在这里插入图片描述

10.task线程完成标识

在这里插入图片描述

六、.net4.5 parallel

1.parallel启动多线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.parallel线程停止

在这里插入图片描述

七、threadcore

1.异常处理

主线程出现异常没人管理会导致程序崩溃
在这里插入图片描述
在这里插入图片描述

  try {TaskFactory taskFactory = new TaskFactory();List < Task > tasklist = new List<Task>();//异常处理for(int i =0;i<20; i++){string name = string.Format($"btn_click_{i}");Action<object> act = t =>{try{Thread.Sleep(2000);if (t.ToString().Equals("btn_click_11")){throw new Exception(string.Format($"{t}执行失败"));}if (t.ToString().Equals("btn_click_12")){throw new Exception(string.Format($"{t}执行失败"));}Console.WriteLine("{0}执行成功", t);}catch (Exception ex){Console.WriteLine(ex.Message);}};tasklist.Add(taskFactory.StartNew(act, name));};Task.WaitAll(tasklist.ToArray());}catch (AggregateException aex){foreach(var item in aex.InnerExceptions){Console.WriteLine(item.Message);}}catch(Exception ex){Console.WriteLine(ex.Message);}

2.线程取消

在这里插入图片描述
tasklist.Add(taskFactory.StartNew(act, name))时,
在这里插入图片描述
tasklist.Add(taskFactory.StartNew(act, name,cts.Token))时,
在这里插入图片描述

 try {TaskFactory taskFactory = new TaskFactory();List < Task > tasklist = new List<Task>();CancellationTokenSource cts = new CancellationTokenSource();for(int i =0;i<40; i++){string name = string.Format($"btn_click_{i}");Action<object> act = t =>{try{/*if (cts.IsCancellationRequested){Console.WriteLine("{0}取消一个任务的执行",t);}*/Thread.Sleep(2000);if (t.ToString().Equals("btn_click_11")){throw new Exception(string.Format($"{t}执行失败"));}if (t.ToString().Equals("btn_click_12")){throw new Exception(string.Format($"{t}执行失败"));}/*else{Console.WriteLine("{0}执行成功", t);}*/if (cts.IsCancellationRequested){Console.WriteLine("{0}放弃执行", t);return;}else{Console.WriteLine("{0}执行成功", t);}}catch (Exception ex){cts.Cancel();Console.WriteLine(ex.Message);}};tasklist.Add(taskFactory.StartNew(act, name,cts.Token));}Task.WaitAll(tasklist.ToArray());}catch (AggregateException aex){foreach(var item in aex.InnerExceptions){Console.WriteLine(item.Message);}}catch(Exception ex){Console.WriteLine(ex.Message);}

3.多线程临时变量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.线程安全lock(lock锁的是引用)

在这里插入图片描述

4.1线程安全问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.2线程共有变量存在线程安全问题

在这里插入图片描述

4.3lock锁原理

只有一个线程可以进去,没有并发 ,解决问题但牺牲性能
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
建议使用微软定义的锁
在这里插入图片描述

private static readonly object btn_click_lock = new object();//引用型变量private int TotalCount = 0;private List<int> IntList = new List<int>();private void button1_Click(object sender, EventArgs e){Console.WriteLine($"[------------主线程start: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");TaskFactory taskFactory = new TaskFactory();//private static readonly object btn_click_lock = new object();List<Task> tasklist = new List<Task>();for (int i = 0; i< 10000; i++){int newI = i;/*//非多线程this.TotalCount += 1;this.IntList.Add(newI);*///多线程tasklist.Add(taskFactory.StartNew(() => {// int m = 3 + 2;lock (btn_click_lock) { this.TotalCount += 1;this.IntList.Add(newI);}}));}Task.WaitAll(tasklist.ToArray());Console.WriteLine(this.TotalCount);Console.WriteLine(this.IntList.Count());Console.WriteLine($"[------------主线程end: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");}

八、.net.0 await/async

在这里插入图片描述

1.await原理

在这里插入图片描述
在这里插入图片描述

await后的代码相当于回调,只不过不是自己写的,是编译器状态机自带的。
回调方法continuewith是子线程完成的,但await不仅仅是回调(可子线程可主线程,计算机分配),所以他们又有所不同

在这里插入图片描述

1.1小代码测试原理

在这里插入图片描述

2.带与不带返回值的async方法

2.1只有asynic

在这里插入图片描述

2.2asynic\await成对出现

await 后面是要跟带有返回值的方法
在定义方法时,有了async和await套装后,尽管方法没有return,但此方法也可看成是带返回值的

不使用返回值
在这里插入图片描述
使用返回值
在这里插入图片描述

2.3t.Wait()与await t区别

在这里插入图片描述

2.4await反编译-相当于状态机

在这里插入图片描述
在这里插入图片描述

3.此知识点代码

 private void button1_Click(object sender, EventArgs e){testshow();}public static void testshow(){test();}private async static Task test(){Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");{//NoReturnNoAwait();NoReturn();for (int i = 0; i < 10; i++){Thread.Sleep(300);Console.WriteLine($"main thread task managedthreadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}--i={i}");}}}private static async void NoReturn(){//主线程执行Console.WriteLine($"NoReturn sleep before await ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");TaskFactory taskFactory = new TaskFactory();Task task = taskFactory.StartNew(() => {Console.WriteLine($"NoReturn sleep before  ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");Thread.Sleep(300);Console.WriteLine($"NoReturn sleep after  ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");});await task;Console.WriteLine($"NoReturn sleep after await ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");}private static async void NoReturnNoAwait(){            //主线程执行Console.WriteLine($"NoReturnNoAwait sleep before task ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");Task task = Task.Run(() =>{Console.WriteLine($"NoReturnNoAwait sleep before  ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");Thread.Sleep(300);Console.WriteLine($"NoReturnNoAwait sleep after  ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");});Console.WriteLine($"NoReturnNoAwait sleep after task ,threadid={Thread.CurrentThread.ManagedThreadId.ToString("00")}---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");}

九、双色球项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.代码

知识点
1.7个独立任务,要多线程计算,启动7个线程后,线程内存while一直计算
2.子线程不能更新界面,所以要this.Updatelbl(lbl, sNumber)实现
3.通过while (this.isgoon)从外面终止7个线程
4.通过lock (llock)对7个子线程进行加锁,避免7个线程同一时刻的值是一样的
5.子线程等待,更新界面 if (!this.isexsit(“00”) && !this.blue.Text.Equals(“00”))
6.所有子线程都执行完后回调taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t => this.ShowResult() );//

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace 双色球
{public partial class Form1 : Form{public Form1(){InitializeComponent();this.start.Enabled = true;this.stop.Enabled = false;}private string[] rednums = { "01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33"};private string[] bluenums = {"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16"};private static readonly object llock =new object();private bool isgoon = true;private List<Task> tasklist = new List<Task>();private void start_Click(object sender, EventArgs e){try{this.start.Text = "运行ing";this.start.Enabled = false;this.isgoon = true;this.tasklist = new List<Task>();this.blue.Text = "00";this.label1.Text = "00";this.label2.Text = "00";this.label3.Text = "00";this.label4.Text = "00";this.label5.Text = "00";this.label6.Text = "00";Console.WriteLine(new Random().Next(0, 15));Console.WriteLine(new Random().Next(0, 15));Console.WriteLine(new Random().Next(0, 15));Console.WriteLine(new Random().Next(0, 15));Thread.Sleep(1000);TaskFactory taskFactory = new TaskFactory(); foreach(var control in this.groupBox1.Controls){if (control is Label)//标签中{Label lbl = (Label)control;if (lbl.Name.Contains("blue")) //blue{tasklist.Add( taskFactory.StartNew(() =>{while (this.isgoon){int indexNum1 = Getrandombnumlong(0, bluenums.Length);string sNumber = this.bluenums[indexNum1];// lbl.Text = sNumber;this.Updatelbl(lbl, sNumber);}}));}else//red{tasklist.Add( taskFactory.StartNew(() =>{while (this.isgoon){int indexNum1 = Getrandombnumlong(0, this.rednums.Length);string sNumber = this.rednums[indexNum1];// lbl.Text = sNumber;lock (llock){if (this.isexsit(sNumber))//加锁防止random出现一样的值{continue;//重复数据时放弃更新}this.Updatelbl(lbl, sNumber);//7个线程访问的是内存中同一个string sNumber,加锁防止取到的值是重复的,}}}));}}}//Thread.Sleep(3000);//直接等3000ms让stop开关enable,不靠谱,有可能有的线程因为数据重复,text没有更新//this.stop.Enabled = true;/*while (true){Thread.Sleep(1000);if (!this.isexsit("00") && !this.blue.Text.Equals("00")){this.stop.Enabled = true;break;}}*/Task.Run(()=> { while (true){Thread.Sleep(1000);if (!this.isexsit("00") && !this.blue.Text.Equals("00")){this.Invoke(new Action(()=>{this.stop.Enabled = true;//子线程操控不了主线程控件,需要主线程来完成}));break;}}});taskFactory.ContinueWhenAll(this.tasklist.ToArray(), t => this.ShowResult() );//所有子线程都执行完}catch(Exception ex){Console.WriteLine("双色球启动出现异常:{0}",ex.Message);}}private void stop_Click(object sender, EventArgs e){this.start.Enabled = true;this.stop.Enabled = false;this.isgoon = false;//Task.WaitAll(this.tasklist.ToArray());//主线程等着全部任务完成,子任务还需要主线程干活更新label,所以又是死锁//this.ShowResult();}private void ShowResult(){MessageBox.Show(string.Format("本期双色球为:{0} {1} {2} {3} {4} {5}   蓝球{6}", this.label1.Text, this.label2.Text, this.label3.Text, this.label4.Text, this.label5.Text, this.label6.Text, this.blue.Text     ));}//更新界面private void Updatelbl(Label lbl ,string text){if (lbl.InvokeRequired){//这里的this指的是winform窗体主UI线程,让UI线程去更新text值this.Invoke(new Action(()=>{//if (this.isgoon) //不延迟,点了就不更新// { lbl.Text = text;Console.WriteLine($"当前update线程id{Thread.CurrentThread.ManagedThreadId}");// }}));}else{lbl.Text = text;}}//验证标签中的text是否有相同的值private bool isexsit(string snumber){foreach (var control in this.groupBox1.Controls){if (control is Label)//标签中的{Label lbl = (Label)control;if (lbl.Name.Contains("label")){if (lbl.Text.Equals(snumber)){return true;}}}}return false;}public int Getrandombnumlong(int min , int max){int indexNum = new Random().Next(min, max);Thread.Sleep(1000);return indexNum;}}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十、知识点代码汇总

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace multithread
{public class Class1{private void dosomething(string name){Console.WriteLine($"[****Dosomething {name} start: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}*******]");}////Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");private void mainpoints() {//1委托调用Action<string> action = this.dosomething;//委托带参数Action action1 = () => this.dosomething("CC");//委托不带参数action.Invoke("AA");//同步调用委托action("BB");//同步调用委托action.BeginInvoke("cc", null, null);//异步调用委托for (int i = 0; i < 5; i++){string name = string.Format($"btn_click_{i}");action.BeginInvoke(name, null, null);//异步多线程}List<Task> tasklist = new List<Task>();TaskFactory taskFactory = new TaskFactory();string name1 = string.Format($"btn_click");CancellationTokenSource cts = new CancellationTokenSource();Action<object> act = t =>{if (t.ToString().Equals("btn_click_11")){throw new Exception(string.Format($"{t}执行失败"));}};tasklist.Add(taskFactory.StartNew(act, name1, cts.Token));//2.委托执行完后进行回调//标准写法AsyncCallback callback = new AsyncCallback(i => Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]"));//简单写法AsyncCallback callback1 = i =>{Console.WriteLine($"[------------到这里计算完成: 线程号:({Thread.CurrentThread.ManagedThreadId.ToString("00")})---{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}-----]");};action.BeginInvoke("cc", callback, null);//回调1 -异步action执行完才会执行回调-action.BeginInvoke("cc", callback, "nimen")-1IAsyncResult asyncResult = null;asyncResult = action.BeginInvoke("cc", callback, "nimen");//回调1 - 异步action执行完才会执行回调 - action.BeginInvoke("cc", callback, "nimen")-2action.BeginInvoke("cc", r =>{Console.WriteLine("11");}, "nimen");//回调2 -异步action执行完才会执行回调-(!asyncResult.IsCompleted)while (!asyncResult.IsCompleted){Console.WriteLine($"文件上传99.9%..");}//回调3 -异步action执行完才会执行回调--信号量WaitOne()asyncResult.AsyncWaitHandle.WaitOne();//等待异步任务完成后,才打印计算完成asyncResult.AsyncWaitHandle.WaitOne(2000);//限时等待// 回调4 - 异步action执行完才会执行回调 - EndInvoke拿到委托函数的返回值Func<int> func = () =>{return DateTime.Now.Day;};Console.WriteLine($"func.Invoke()={ func.Invoke()}");IAsyncResult asyncResult1 = func.BeginInvoke(r =>{Console.WriteLine(r.AsyncState);}, "nimen");Console.WriteLine($"func.EndInvoke={ func.EndInvoke(asyncResult1)}");//3.thread//3.1.线程启动 thread.Start();ThreadStart threadStart = () => this.dosomething("cc");Thread thread = new Thread(threadStart);thread.Start();//3.2.线等待程thread.Join();thread.Join(500);//卡主线程Console.WriteLine($"等待500ms");thread.Join();//3.3.thread.ThreadState /thread.IsBackfroundwhile (thread.ThreadState != ThreadState.Stopped){Thread.Sleep(100);//cpu时间片交出去干其他的事,但是内存还是占用}thread.IsBackground = true;//前台线程,当软件闪退时,会吐出日志//4.threadPool//4.1ThreadPool.GetMaxThreadsThreadPool.QueueUserWorkItem(t =>{ this.dosomething("cc");this.dosomething("dd");});//接收一个没有返回值的委托ThreadPool.SetMaxThreads(16, 16);ThreadPool.GetMaxThreads(out int Workerthreads, out int completionPortThreads);Console.WriteLine($"Workerthreads:{Workerthreads}+completionPortThreads{completionPortThreads}");//4.2.manualResetEventManualResetEvent manualResetEvent = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(t =>{this.dosomething("cc");manualResetEvent.Set();});//接收一个没有返回值的委托manualResetEvent.WaitOne();Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");//5.taskTask.Run(() =>{this.dosomething("cc");Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");});new Task(() => this.dosomething("33")).Start();TaskFactory taskFactory1 = Task.Factory;taskFactory.StartNew(() => this.dosomething("44"));//5.1 task.waitall、waitany  .ContinueWith taskFactory.ContinueWhenAnyList<Task> tasklist1 = new List<Task>();tasklist.Add(Task.Run(() => this.dosomething("33")));tasklist.Add(Task.Run(() => this.dosomething("33")));Task.WaitAny(tasklist.ToArray());Task.WaitAll(tasklist.ToArray());Task.WhenAll(tasklist.ToArray()).ContinueWith(t =>{Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");});taskFactory.ContinueWhenAny(tasklist.ToArray(), t => { });//5.2 task线程完成标识Task task = new Task(t => { }, "CC");Console.WriteLine(task.AsyncState);//会打印CC//5.3thread.sleep()卡线程 task.delay()不卡线程//5.4tasklist线程取消CancellationTokenSource cts1 = new CancellationTokenSource();tasklist.Add(taskFactory.StartNew(() => this.dosomething("44"), cts1.Token));//6.parallel启动多线程Parallel.Invoke(() => this.dosomething("11"),() => this.dosomething("22"),() => this.dosomething("33"));//6.1Parallel.ForParallel.For(0, 5, i => this.dosomething(i));Parallel.ForEach(new string[] { "0","1","2","3"},i=>this.dosomething("11"));//6.2控制并发数量ParallelOptions parallelOptions = new ParallelOptions();parallelOptions.MaxDegreeOfParallelism = 3;Parallel.For(0,40,parallelOptions,(i,state)=> { if (i==2){state.Break();state.Stop();}});//7.线程安全lock//private static readonly object btn_click = new object();int c = 0;tasklist.Add(taskFactory.StartNew(() => {int m = 3 + 2;lock (btn_click){c += 1;}}));//8.await/asyncawait 后的代码相当于回调,只不过不是自己写的,是编译器状态机自带的。//回调方法continuewith是子线程完成的,但await不仅仅是回调(可子线程可主线程,计算机分配),所以他们又有所不同private static async void Async(){await Task.Run(() => {Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");});Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/111712.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

knife4j 整合 springboot

官方文档&#xff1a;https://doc.xiaominfo.com/knife4j 版本兼容说明&#xff1a;https://doc.xiaominfo.com/docs/quick-start/start-knife4j-version 升级说明&#xff1a;https://doc.xiaominfo.com/docs/upgrading/upgrading-to-v4版本兼容惯关系&#xff1a; springboot…

6. vue-element-admin 二次开发避坑指南

vue-element-admin 二次开发避坑指南 1.1 前言1.1.1 切换标签时未保存页面的操作内容1.1.2 markdown 样式乱码1.1.3 修改默认尺寸1.1.4 当后端服务器宕机情况下页面加载层一直转圈无法停止&#xff0c;只能关闭页面1.1.5 隐藏齿轮 1.1 前言 上一篇博文&#xff0c;我们分享了vu…

Redis——如何解决redis穿透、雪崩、击穿问题

目录 一、查询商品信息的常规代码示例二、缓存击穿2.1、缓存击穿的理解2.2、缓存击穿的解决方案2.3、解决缓存击穿的代码示例 三、缓存雪崩3.1、缓存雪崩的理解3.2、缓存雪崩的解决方案3.2.1、缓存集中过期的情况3.2.2、缓存服务器宕机的情况3.2.3、缓存服务器断电的情况 3.3、…

性能测试常见的测试指标

一、什么是性能测试 先看下百度百科对它的定义 性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。我们可以认为性能测试是&#xff1a;通过在测试环境下对系统或构件的性能进行探测&#xff0c;用以验证在生产环境下系统性能…

【卷积神经网络】MNIST 手写体识别

LeNet-5 是经典卷积神经网络之一&#xff0c;1998 年由 Yann LeCun 等人在论文 《Gradient-Based Learning Applied to Document Recognition》中提出。LeNet-5 网络使用了卷积层、池化层和全连接层&#xff0c;实现可以应用于手写体识别的卷积神经网络。TensorFlow 内置了 MNI…

Geodetector 应用excel显示宏损坏的解决办法

打开地理探测器 如果显示宏损坏&#xff0c;每次excel会自动删除文件中的宏文件&#xff0c;导致地理探测器不能运行&#xff0c;这样的解决办法主要是&#xff1a;修改电脑本身格式与excel宏文件运行格式一致&#xff1a; 区域格式改为中文&#xff0c;这样就可以运行了。

记一次坑爹的ARouter::There is no route match the path

接入阿里的ARouter框架&#xff1b;实现最简单的页面跳转&#xff1b;一直失败&#xff0c;报找不到匹配的路径&#xff1b;百度各种基本都说配置有问题&#xff1b;我一一对应&#xff0c;配置怎么看看不出问题来&#xff1b; 我的架构是 接入的代码怎么看都没问题&#xff1…

动态维护直径 || 动态维护树上路径 || 涉及LCA点转序列 || 对欧拉环游序用数据结构维护:1192B

https://www.luogu.com.cn/problem/CF1192B 对于直径的求法&#xff0c;常用dp或两次dfs&#xff0c;但如果要动态维护似乎都不太方面&#xff0c;那么可以维护树上路径最大值。 树上路径为&#xff1a; d e p u d e p v − 2 d e p l c a ( u , v ) dep_udep_v-2\times de…

图解算法--查找算法

目录 查找算法 一、顺序查找 二、二分法查找 三、插值查找法 四、斐波那契查找法 查找算法 查找算法根据数据量的大小&#xff0c;可以将其分为以下两种 内部查找&#xff1a;内部查找是指在内存或内部存储器中进行查找操作的算法。内部查找适用于数据量较小、存储在内存…

概念解析 | 量子机器学习:将量子力学与人工智能的奇妙融合

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:量子机器学习。 量子机器学习:将量子力学与人工智能的奇妙融合 量子增强机器学习:量子经典混合卷积神经网络 量子机器学习是量子计算和机器学习的结合,它利用量子力学的特…

探讨uniapp的路由与页面栈及参数传递问题

1首先引入页面栈 框架以栈的形式管理当前所有页面&#xff0c; 当发生路由切换的时候&#xff0c;页面栈的表现如下&#xff1a; 页面的路由操作无非&#xff1a;初始化、打开新页面、页面重定向、页面返回、tab切换、重加载。 2页面路由 uni-app 有两种页面路由跳转方式&am…

【实训项目】精点考研

1.设计摘要 如果说高考是一次能够改变命运的考试&#xff0c;那么考研应该是另外一次。为什么那么多人都要考研呢&#xff1f;从中国教育在线官方公布是考研动机调查来看&#xff0c;大家扎堆考研的原因大概集中在这6个方面&#xff1a;本科就业压力大&#xff0c;提升竞争力、…

视频汇聚/视频云存储/视频监控管理平台EasyCVR视频平台添加萤火云设备的具体操作步骤

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

解析肖特基二极管NRVBS360BNT3G整流器的优缺点及应用

何为肖特基二极管整流器&#xff1f; 是一种常用的电子器件&#xff0c;用于将交流信号转换为直流信号。它由一个PN结和一个金属接触组成&#xff0c;具有较低的正向压降和快速的开关特性。 在正向偏置下&#xff0c;肖特基二极管具有较低的正向压降&#xff0c;通常为0.3-0.…

笔记本电脑功率怎么看?记好这2个方法!

在使用笔记本电脑时&#xff0c;其功率是一个很重要的指标。笔记本电脑功率是影响其性能、续航和热管理的重要因素。不同的功率水平可以带来不同的使用体验。 本文将解释不同的笔记本电脑功率对设备的影响&#xff0c;并详细介绍几种查看笔记本电脑功率的方法。继续往下看吧&a…

安全生产作业现场违规行为识别 opencv

安全生产作业现场违规行为识别算法通过pythonopencv网络模型算法框架设定了各种合规行为和违规行为的模型&#xff0c;安全生产作业现场违规行为识别算法检测到违规行为&#xff0c;将立即进行抓拍并发送告警信息给相关人员&#xff0c;以便及时采取相应的处置措施。OpenCV是一…

基于OV2640/ OV5640 的图像采集显示系统

基于OV2640/ OV5640 的图像采集显示系统系列文章目录&#xff1a; &#xff08;1&#xff09;基于 OV5640 摄像头理论知识讲解-成像和采样原理 &#xff08;2&#xff09;基于 OV5640 摄像头理论知识讲解-数字接口和控制接口 &#xff08;3&#xff09;基于 OV5640 摄像头理论知…

vscode+ros开发环境搭建

目录 介绍 前提 vscode安装 vscode插件安装 工作空间准备 打开vscode 创建catkin包 编写cpp代码 编译 运行 启动ros服务 监听话题 启动ros测试 介绍 ros开发是机器人开发中必不可少的工作&#xff0c;语言选择可以是c,也可以是python。工具的话&#xff0c;不能像wi…

ceph中PGLog处理流程

ceph的PGLog是由PG来维护&#xff0c;记录了该PG的所有操作&#xff0c;其作用类似于数据库里的undo log。PGLog通常只保存近千条的操作记录(默认是3000条&#xff0c; 由osd_min_pg_log_entries指定)&#xff0c;但是当PG处于降级状态时&#xff0c;就会保存更多的日志&#x…

React 生命周期

React的生命周期 一、什么是React的生命周期二、传统生命周期2.1、挂载&#xff08;Mounting&#xff09;2.2、更新&#xff08;Updating&#xff09;2.3、卸载&#xff08;Unmounting&#xff09;2.4、API2.4.1、render2.4.1.1、Updating 阶段&#xff0c;render调用完还有可能…