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.代码
  • 十、知识点代码汇总

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

线程:程序执行的最小单位,任何操作都是由线程完成的,使用同步时,资源一直被此线程占用,所以其他界面干不了,会出现卡界面的现象。
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第1张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第2张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第3张图片

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第4张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第5张图片
1启动不可控制、2结束不可控
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第6张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第7张图片
一个耗时(i++)、耗资源(thread.sleep)的方法
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第8张图片

二、四种异步等待方式

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

action执行完将asyncResult、"nimen"当成参数传给callback
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第9张图片

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

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

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

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

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

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

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 action = this.dosomething;
                action.Invoke("AA");//同步调用委托
                action("BB");//同步调用委托
                action.BeginInvoke("cc", null, null);//异步调用委托
            }
            

            /*2异步-不可控
            {
                Action action = this.dosomething;
                for (int i = 0; i < 5; i++)
                {
                    string name = string.Format($"btn_click_{i}");
                    action.BeginInvoke(name, null, null);//异步调用委托
                }
             }*/

            /*3.异步不可控
            { 
               
                Action 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 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 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 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 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 action = this.dosomething;
                Func 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 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时间片交出去干其他的事,但是内存还是占用
                }

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

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

thread.join(500),是其他人线程等他500ms,此时有两个线程在工程, 一个在等待500ms,一个是自己在运行
thread.sleep(500),是自己线程自己将cpu时间片交出去干其他的事,但是内存还是占用,休眠500ms
前台线程,当软件闪退时,会吐出日志
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第15张图片

四、net 2.0 threadpool

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

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

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

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

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

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第19张图片
waitone()风险,无线程可用会卡住
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第20张图片

3.手写异步回调函数

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

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

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

五、.net3.0 task

1.task线程启动

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

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

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第24张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第25张图片
waitall、waitany应用场景
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第26张图片

3.task.whenall.continuewith()

首先task.whenall不卡主界面,快快的结束了btn_task_click是主线程任务
其次continuewith() ,当tasklist中线程执行后并满足条件时(all\any),直接顺序执行下面的委托,类似回调如“得意的笑”
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第27张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第28张图片

4.taskfactory.continuewith()

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

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

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

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

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

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

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

8.两个waitall按顺序执行

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

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

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

10.task线程完成标识

在这里插入图片描述

六、.net4.5 parallel

1.parallel启动多线程

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第38张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第39张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第40张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第41张图片

2.parallel线程停止

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

七、threadcore

1.异常处理

主线程出现异常没人管理会导致程序崩溃
在这里插入图片描述
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第43张图片

  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.线程取消

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第44张图片
tasklist.Add(taskFactory.StartNew(act, name))时,
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第45张图片
tasklist.Add(taskFactory.StartNew(act, name,cts.Token))时,
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第46张图片

 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.多线程临时变量

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

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

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

4.1线程安全问题

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

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

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

4.3lock锁原理

只有一个线程可以进去,没有并发 ,解决问题但牺牲性能
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第55张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第56张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第57张图片
建议使用微软定义的锁
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第58张图片

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

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

1.await原理

在这里插入图片描述
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第60张图片

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

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

1.1小代码测试原理

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

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

2.1只有asynic

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

2.2asynic\await成对出现

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

不使用返回值
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第64张图片
使用返回值
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第65张图片

2.3t.Wait()与await t区别

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

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

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

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")}");
        }

九、双色球项目

c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第69张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第70张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第71张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第72张图片
c#多线程—基础概念到“双色球”项目实现(附知识点目录、代码、视频)_第73张图片

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;
        }


    }
}

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

十、知识点代码汇总

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执行完再执行");
            }

        }
    }



}

你可能感兴趣的:(C#,c#)