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")-1
            IAsyncResult asyncResult = null;
            asyncResult = action.BeginInvoke("cc", callback, "nimen");

            //回调1 - 异步action执行完才会执行回调 - action.BeginInvoke("cc", callback, "nimen")-2
            action.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.IsBackfround
            while (thread.ThreadState != ThreadState.Stopped)
            {
                Thread.Sleep(100);//cpu时间片交出去干其他的事,但是内存还是占用
            }
            thread.IsBackground = true;//前台线程,当软件闪退时,会吐出日志

            //4.threadPool
            //4.1ThreadPool.GetMaxThreads
            ThreadPool.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.manualResetEvent
            ManualResetEvent manualResetEvent = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(t =>
            {
                this.dosomething("cc");
                manualResetEvent.Set();
            });//接收一个没有返回值的委托
            manualResetEvent.WaitOne();
            Console.WriteLine($"等待ThreadPool.QueueUserWorkItem执行完再执行");

            //5.task
            Task.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.ContinueWhenAny
            List<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.For
            Parallel.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.mfbz.cn/a/100690.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS—使用Web组件加载页面

页面加载是 Web 组件的基本功能。根据页面加载数据来源可以分为三种常用场景&#xff0c;包括加载网络页面、加载本地页面、加载 HTML 格式的富文本数据。 页面加载过程中&#xff0c;若涉及网络资源获取&#xff0c;需要配置ohos.permission.INTERNET网络访问权限。 加载网络…

QEMU 仿真RISC-V freeRTOS 程序

1. 安裝RISC-V 仿真環境 --QEMU 安裝包下載地址: https://www.qemu.org/ 安裝命令及安裝成功效果如下所示, target-list 設定爲riscv32-softmmu, $ cat ~/project/qemu-8.0.4/install.sh sudo apt-get install libglib2.0-dev sudo apt-get install libpixman-1-dev ./co…

【MySQL】基础语法总结

MySQL 基础语句 一、DDL 数据库定义语言 1.1CREATE 创建 1.1.1 创建数据库 语法结构 CREATE DATABASE database_name;示例 CREATE DATABASE demo;1.1.2 创建表 语法结构 CREATE TABLE 表名 (列1 数据类型,列2 数据类型,... );示例 CREATE TABLE new_user (id INT PRIMARY KE…

软考A计划-网络工程师-复习背熟-数据通信基础和局域网技术

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

2.3 数据模型

思维导图&#xff1a; 前言&#xff1a; 我的理解&#xff1a; 这段话介绍了概念模型和数据模型之间的关系&#xff0c;以及数据模型的定义和重要性。具体解读如下&#xff1a; 1. **概念模型**&#xff1a;它是一种描述现实世界数据关系的抽象模型&#xff0c;不依赖于任何…

深度学习经典检测方法的概述

深度学习经典的检测方法 two-stage&#xff08;两阶段&#xff09;&#xff1a;Faster-rcnn Mask-Rcnn系列 两阶段&#xff08;two-stage&#xff09;是指先通过一个区域提取网络&#xff08;region proposal network&#xff0c;RPN&#xff09;生成候选框&#xff0c;再通过…

信息技术01--初/高中--选择真题汇总(197道题)

文章目录 1 真题 01-102 真题 11-203 真题 21-304 真题 31-405 真题 41-506 真题 51-607 真题 61-708 真题 71-809 真题 81-9010 真题 91-10011 真题 101-11012 真题 111-12013 真题 121-13014 真题 131-14015 真题 141-15016 真题 151-16017 真题 161-17018 真题 171-18019 真…

计算机网络 概述部分

目录 计算机网络在信息时代的作用 计算机网络的重要特征 网络&#xff0c;internet,Internet的区别 局域网 广域网的区别 网络协议的分层 计算机网络在信息时代的作用 计算机网络的重要特征 连通性&#xff1a;彼此联通&#xff0c;交换信息 共享性&#xff1a;信息共享…

FPGA时序分析与约束(3)——时钟不确定性

一、前言 在之前的文章中&#xff0c;我们介绍了组合电路的时序和时序电路的时序问题&#xff0c;在阅读本文章之前&#xff0c;强烈推荐先阅读完本系列之前的文章&#xff0c;因为这是我们继续学习的理论的理论基础&#xff0c;前文链接&#xff1a; FPGA时序分析与约束&…

【K8S系列】深入解析k8s网络插件—Cilium

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 在现代容器化应用程序的世界中…

朝夕光年游戏自动化测试实践

朝夕光年是面向全球用户与开发者的游戏研发与发行业务品牌&#xff0c;致力于服务全球玩家&#xff0c;帮助玩家在令人惊叹的虚拟世界中一起玩耍与创造。 在游戏的研发过程中&#xff0c;游戏自动化一直是开展难度较大的工程&#xff0c;具体包括机房机架、设备调度、软件框架、…

【Pandas 入门-5】Pandas 画图

Pandas 画图 除了结合 matplotlib 与 seaborn 画图外&#xff0c;Pandas 也有自己的画图函数plot&#xff0c;它的语法一般为&#xff1a; DataFrame.plot(xNone,yNone, kindline,subplotsFalse, titleNone)x横坐标数据y纵坐标数据kind默认是线图&#xff0c;还可以是‘bar’…

c++ opencv将彩色图像按连通域区分

要将彩色图像按连通域区分&#xff0c;您可以使用 OpenCV 中的 cv::connectedComponents 函数。 下面是一个简单的示例代码&#xff0c;说明如何使用 cv::connectedComponents 函数来检测并标记图像中的连通域&#xff1a; #include <opencv2/opencv.hpp> #include <…

Docker技术--Docker中的网络问题

1.docker中的网络通信 如果想要弄清楚docker中的网络通信问题,其实需要弄清楚这几个问题就可以:容器与容器之间的通信、容器与外部网络之间的通信、外部网络与容器之间的通信。 -a:容器与容器之间的通信,如下所示: 在默认情况下,docker使用网桥(Bridge模式)与NAT通信。这…

CSS中你不得不知道的css优先级

在我们定义css样式时&#xff0c;经常出现两个或更多规则应用在同一元素上&#xff0c;这时就会出现优先级的问题。其实css为每一种基础选择器都分配了一个权重。 我们简化理解&#xff1a; CSS权重计算&#xff1a; 最顶层&#xff1a;!important 权重值&#xff1a;…

算法通关村14关 | 堆结构

1. 堆的概念与特征 堆是将一组数据按照完全二叉树的存储顺序&#xff0c;将数据存储在一维数组中的结构&#xff0c;对的结构有两种&#xff0c;一种称为大顶堆&#xff0c;一种称为小顶堆。 小顶堆&#xff1a;任意节点的值均小于等于它的左右孩子&#xff0c;并且最小的值位于…

数据通信——传输层TCP(可靠传输原理的ARQ)

引言 上一篇讲述了停止等待协议的工作流程&#xff0c;在最后提到了ARQ自动请求重传机制。接下来&#xff0c;我们就接着上一篇的篇幅&#xff0c;讲一下ARQ这个机制 还是这个图来镇楼 ARQ是什么&#xff1f; 发送端对出错的数据帧进行重传是自动进行的&#xff0c;因而这种…

【iOS】折叠cell

文章目录 前言一、实现效果二、折叠cell的实现原理三、实现折叠cell的高度变化四、实现选中点击的单元格总结 前言 在暑假的3GShare中用到了折叠cell控件&#xff0c;特此总结博客记录 一、实现效果 二、折叠cell的实现原理 首先我们需要知道ScrollView的是TableView的父类&a…

Java从入门到精通-流程控制(一)

流程控制 1.复合语句 复合语句&#xff0c;也称为代码块&#xff0c;是一组Java语句&#xff0c;用大括号 {} 括起来&#xff0c;它们可以被视为单个语句。复合语句通常用于以下情况&#xff1a; - 在控制结构&#xff08;如条件语句和循环&#xff09;中包含多个语句。 - …

肖sir__linux详解__002(系统命令)

linux系统命令 1、df 查看磁盘使用情况 &#xff08;1&#xff09;df 查看磁盘使用情况&#xff08;按kb单位显示&#xff09; &#xff08;2&#xff09;df -h 按单位显示磁盘使用情况 2、top 实时查看动态进程 &#xff08;1&#xff09;top 详解&#xff1a; 第一行&…
最新文章