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

news2024/11/20 10:45:33

总结:视频中对于多线程讲的非常透彻,从线程基础概念—>.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.coloradmin.cn/o/945701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新建Spring Boot项目

使用IDEA 来创建: 文件-新建-项目 填写项目元数据 选择依赖项 此处可以先选 web-spring web 关于这些依赖项&#xff0c;更多可参考&#xff1a; IDEA创建Spring boot项目时各依赖的说明&#xff08;Developer Tools篇&#xff09;[1] 项目结构介绍 展开项目&#xff0c;此时…

redis应用 2:延时队列

我们平时习惯于使用 Rabbitmq 和 Kafka 作为消息队列中间件&#xff0c;来给应用程序之间增加异步消息传递功能。这两个中间件都是专业的消息队列中间件&#xff0c;特性之多超出了大多数人的理解能力。 使用过 Rabbitmq 的同学知道它使用起来有多复杂&#xff0c;发消息之前要…

socket的TCP和UDP样例

【70天稳扎稳打学完JavaEE初阶】 TCP和UDP的区别及相关的不同应用 UDP实现回显功能一、UdpEchoServer服务器二、UdpEchoClient 客户端写一个 翻译服务器&#xff08;继承服务器&#xff09; UDP示例二&#xff1a;展示服务器本地某个目录的下一级子文件列表服务UDP服务器UDP客户…

什么是ChatGPT水印,ChatGPT生成的内容如何不被检测出来,原理什么?

太长不看版 1. 什么是ChatGPT水印&#xff1f; ChatGPT水印是AI以伪随机方式生成的独特tokens序列。该序列用来作为水印&#xff0c;以区分AI生成内容和人类原创内容。 2. 如何规避ChatGPT水印&#xff1f; 一种规避方法是使用其他AI模型改写ChatGPT生成的文本。这会破坏水…

Nat. Mach. Intell 2020 | drugVQA+:准VAQ系统预测药物-蛋白质相互作用

论文标题&#xff1a;Predicting drug–protein interaction using quasi-visual question answering system 论文地址&#xff1a;Predicting drug–protein interaction using quasi-visual question answering system | Nature Machine Intelligence 代码&#xff1a;GitH…

继承AndroidView Model的错误

ViewModelProvider(this)[RegisterViewModel::class.java] 一行简单的代码&#xff0c;总是报这个错误 Caused by: java.lang.NoSuchMethodException: com.xinfa.registerlogin.viewmodel.LoginViewModel. [class android.app.Application] 经过一下午的思索&#xff0c;终于找…

科普:什么是DNS劫持?

DNS劫持又叫做域名劫持&#xff0c;指攻击者利用其他攻击手段&#xff0c;篡改了某个域名的解析结果&#xff0c;使得指向该域名的IP变成了另一个IP&#xff0c;导致对相应网址的访问被劫持到另一个不可达的或者假冒的网址&#xff0c;从而实现非法窃取用户信息或者破坏正常网络…

我们的第一个 Qt 窗口程序

Qt 入门实战教程&#xff08;目录&#xff09; Windows Qt 5.12.10下载与安装 为何使用Qt Creator开发QT 本文介绍用Qt自带的集成开发工具Qt Creator创建Qt默认的窗口程序。 本文不需要你另外安装Visual Studio 2022这样的集成开发环境&#xff0c;也不需要你再在Visual St…

【单片机】有人WH-LTE-7S1 4G cat1 模块连接服务器,教程,记录

文章目录 4G cat1 模块封装引脚名称功能拓扑图串口模块调试WH-LTE-7S1 4G cat1 模块 我买的这个模块内置了电信卡&#xff0c;不用插电话卡就能用&#xff0c;要插也行&#xff0c;在背面。 ⚫ 5-16V 宽电压供电 ⚫ LTE Cat 1&#xff0c;搭载 4G 网络&#xff0c;低时延&…

2023年腾讯云轻量应用服务器优缺点大全

2023年腾讯云轻量应用服务器优缺点大全&#xff0c;腾讯云轻量应用服务器性能如何&#xff1f;轻量服务器CPU内存带宽配置高&#xff0c;CPU采用什么型号主频多少&#xff1f;轻量应用服务器会不会比云服务器CVM性能差&#xff1f;腾讯云服务器网详解CPU型号主频、内存、公网带…

《存储IO路径》专题:IO虚拟化初探

大家好&#xff0c;欢迎来到今天的科技小课堂。今天我们要聊聊的是一项非常有趣且实用的技术——I/O虚拟化&#xff08;Input/Output Virtualization&#xff0c;简称IOV&#xff09;。想象一下&#xff0c;如果把物理硬件资源比作一道丰盛的大餐&#xff0c;那么IOV就是那位神…

Java 若依框架系统工具生成代码,前后端以及菜单添加使用示例

前言 若依框架不多介绍&#xff0c;目前比较流行的一款开源的后台管理框架&#xff0c;主要技术栈 后台spingboot、spingcloud 前端vue2 vue3版本的都有&#xff0c;可以去官方下载看看。 若依框架提供代码生成的功能&#xff0c;方便我们把简单的增删改查前后端代码生成直接…

【JAVA基础——JAVA8版本特性】

JAVA基础 版本特性 文章目录 JAVA基础Java8Lambda表达式lambda表达式类型 函数式接口接口默认方法与静态方法接口默认方法接口静态方法 方法引用OptionalStream流生产Stream Source的方式流的方法parallelStream流 Date/Time API其他特性重复注解扩展注解参数名字保留在字节码…

绿色能源迎来跨越式增长新时代

当今世界&#xff0c;百年未有之大变局加速演进&#xff0c;新一轮科技革命和产业变革深入发展&#xff0c;全球气候治理呈现新局面&#xff0c;新能源和信息技术紧密融合&#xff0c;生产生活方式加快转向低碳化、智能化&#xff0c;能源体系和发展模式正在进入非化石能源主导…

ROS中使用Navigation报错信息

在ROS中使用遇到了几个Navigation报错信息&#xff0c;在这里进行下记录&#xff1a; [ WARN] [1688134727.429227824]: The origin for the sensor at (7.35, 13.12) is out of map bounds. So, the costmap cannot raytrace for it. 解决办法&#xff1a; [ WARN] [16881…

flink on yarn with kerberos 边缘提交

flink on yarn 带kerberos 远程提交 实现 flink kerberos 配置 先使用ugi进行一次认证正常提交 import com.google.common.io.Files; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.apache.flink.client.cli.CliFrontend; import o…

Gorilla LLM:连接海量 API 的大型语言模型

如果你对这篇文章感兴趣&#xff0c;而且你想要了解更多关于AI领域的实战技巧&#xff0c;可以关注「技术狂潮AI」公众号。在这里&#xff0c;你可以看到最新最热的AIGC领域的干货文章和案例实战教程。 一、前言 在当今这个数字化时代&#xff0c;大型语言模型&#xff08;LLM…

史上最全AP、mAP详解与代码实现

文章目录 前言一、mAP原理1、mAP概念2、准确率3、精确率4、召回率5、AP: Average Precision 二、mAP0.5与mAP0.5:0.951、mAP0.52、mAP0.5:0.95 三、mAP代码实现1、真实标签json文件格式2、模型预测标签json文件格式3、mAP代码实现4、mAP结果显示 四、模型集成mAP代码1、模型mai…

项目:点餐系统3mysql知识回顾MySQL客户端

连接数据库 mysql -uroot -p 密码&#xff1a;空 一、第三方库&#xff1a;MySQL 数据库-存储并管理数据的仓库&#xff0c;是一个C/S架构 MySQL客户端通过sql来告诉MySQL服务器&#xff0c;自己需要做什么操作 1.sql语句 sql&#xff1a;structure query language结构化查询…

LeetCode 44题:通配符匹配

题目 给你一个输入字符串 (s) 和一个字符模式 (p) &#xff0c;请你实现一个支持 ? 和 * 匹配规则的通配符匹配&#xff1a; ? 可以匹配任何单个字符。* 可以匹配任意字符序列&#xff08;包括空字符序列&#xff09;。 判定匹配成功的充要条件是&#xff1a;字符模式必须…