c# multi-threading - basic concepts to "Double Color Ball" project implementation (with knowledge point directory, code, video)

Summary: The video explains multi-threading very thoroughly, from the basic concepts of threads -> Threading methods that appear in different versions of .net -> Common problems with multi-threading -> Shuangseqiu project practice, every knowledge point has code practice, you will benefit from it Very shallow. Attached are study notes and practical code.
video

Table of contents

1. Concepts of threads and processes and their advantages and disadvantages

Thread: The smallest unit of program execution. All operations are completed by threads. When synchronization is used, resources are always occupied by this thread, so other interfaces cannot work, and the interface will be stuck.
Insert image description here
Insert image description here
Insert image description here

Insert image description here
Insert image description here
1. The start is uncontrollable. 2. The end is uncontrollable.
Insert image description here
main thread code
A time-consuming (i++) and resource-consuming (thread.sleep) method
Insert image description here

2. Four asynchronous waiting methods

1. Asynchronous control waiting-callback callback

After the action is executed, asyncResult and "nimen" are passed to the callback as parameters.
Insert image description here

2. Asynchronous control waiting-asyncResult.IsCompleted

Insert image description here

3. Asynchronous control waits for WaitOne()-semaphore

Insert image description here

4. Asynchronous control waits for endinvoke-gets the return value of the asynchronous function

Insert image description here
Insert image description here

5. Video lesson code 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}*******]");

        }

    }
}

3. Thread object of .net1.0 basic version

1. Thread startup

 {
    
    
                //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时间片交出去干其他的事,但是内存还是占用
                }

Insert image description here

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

thread.join(500), other people's threads are waiting for it for 500ms. At this time, there are two threads in the project. One is waiting for 500ms, and the other is running
thread.sleep(500). It is the own thread that hands over the CPU time slice. Go out to do other things, but the memory is still occupied.
The foreground thread sleeps for 500ms. When the software crashes, the log will be spit out.
Insert image description here

4. net 2.0 threadpool

Insert image description here

1. Thread startup and setting the maximum number of threads in the thread pool

Insert image description here
Insert image description here

2.manualResetEvent.WaitOne() asynchronous control waiting

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

Insert image description here
The risk of waitone() is that if no thread is available, it will get stuck.
Insert image description here

3. Handwritten asynchronous callback function

Insert image description here

4. Delegate asynchronous call with return value (French structure to be learned)

Insert image description here

5. .net3.0 task

1.Task thread startup

Insert image description here

2.waitall and waitany will block the main thread interface.

Insert image description here
Insert image description here
waitall, waitany application scenarios
Insert image description here

3.task.whenall.continuewith()

First, task.whenall is not stuck on the main interface and ends quickly. btn_task_click is the main thread task.
Secondly, continuewith(). When the thread in the tasklist is executed and the conditions are met (all\any), the following commissions are executed directly in sequence, similar to the callback such as "smug smile"
Insert image description here
Insert image description here

4.taskfactory.continuewith()

Insert image description here
Insert image description here

5. Designed to have only 11 threads working at most

Insert image description here

6. After taskfactory detects which thread has ended, it returns the thread ID

Insert image description here
Insert image description here

7. Tasks can be nested multiple times to avoid blocking the main thread.

Insert image description here
Insert image description here

8. Two waitalls are executed in sequence

If there are two waitalls that need to be executed but they are in different threads, but the order of the two waitalls must be guaranteed, the solution is to add the first waitall to the tasklist, and then let the waitall of the second task judge.
Insert image description here

9.thread.sleep() thread stuck task.delay() does not stuck thread

Insert image description here
Insert image description here

10.Task thread completion identification

Insert image description here

6. .net4.5 parallel

1.parallel starts multi-threading

Insert image description here
Insert image description here
Insert image description here
Insert image description here

2.Parallel thread stops

Insert image description here

7. Threadcore

1.Exception handling

An exception in the main thread will cause the program to crash if no one manages it.
Insert image description here
Insert image description here

  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. Thread cancellation

Insert image description here
tasklist.Add(taskFactory.StartNew(act, name))时,
Insert image description here
tasklist.Add(taskFactory.StartNew(act, name,cts.Token))时,
Insert image description here

 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. Multi-threaded temporary variables

Insert image description here
Insert image description here
Insert image description here

4. Thread-safe lock (the lock locks the reference)

Insert image description here

4.1 Thread safety issues

Insert image description here
Insert image description here
Insert image description here

4.2 Thread-shared variables have thread safety issues

Insert image description here

4.3Lock principle

Only one thread can enter, there is no concurrency, solving the problem but sacrificing performance.
Insert image description here
Insert image description here
Insert image description here
It is recommended to use Microsoft-defined locks
Insert image description here

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

Insert image description here

1.await principle

Insert image description here
Insert image description here

The code after await is equivalent to a callback, but it is not written by yourself, but comes with the compiler state machine.
The callback method continuewith is completed by the child thread, but await is not just a callback (it can be allocated by the child thread, the main thread, or the computer), so they are different.

Insert image description here

1.1 Principles of small code testing

Insert image description here

2. Async methods with and without return values

2.1 only asynic

Insert image description here

2.2asynic\await appears in pairs

Await should be followed by a method with a return value.
When defining a method, with the async and await suite, although the method does not have a return, this method can also be regarded as having a return value.

Do not use return value
Insert image description here
Use the return value
Insert image description here

2.3 The difference between t.Wait() and await t

Insert image description here

2.4await decompilation-equivalent to state machine

Insert image description here
Insert image description here

3. The code of this knowledge point

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

9. Double Color Ball Project

Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here

1.Code

Knowledge points
1. 7 independent tasks require multi-thread calculation. After starting 7 threads, the thread memory while keeps calculating
2. The child thread cannot update the interface, so this.Updatelbl(lbl, sNumber) is required to implement
3. Through while (this.isgoon) from Terminate 7 threads outside
4. Lock the 7 sub-threads through lock (llock) to prevent the 7 threads from having the same value at the same time
5. The sub-threads wait and update the interface if (!this.isexsit(“00”) && !this.blue.Text.Equals(“00”))
6. After all sub-threads have finished executing, call back 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;
        }


    }
}

Insert image description here
Insert image description here
Insert image description here

10. Summary of knowledge point codes

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

        }
    }



}

Guess you like

Origin blog.csdn.net/m0_46204224/article/details/131756149