• 多线程学习笔记


    工具下载地址:链接: https://pan.baidu.com/s/1mLxHzpE91IFA0AaUELGCpw 提取码: 2vn3 

    一、Windbg的使用

    运行Windbg-->file->Attach to a Process 选择一个进程

    .loadby sos clr 首先需要加载sos和clr

    !threads 显示线程信息

    !teb 显示TEB信息 

    !dumpdomain 显示程序域

    !clrstack 查看当前的调用堆栈(首先需要点击线程的osid)

    点击线程的State可以查看线程的状态 

    !help 帮助命令 

    !FinalizeQueue 查看终结器

    !threadpool 查询线程池

    !dumpheap -stat 查看clr的托管堆中的各个类型的占用情况

    二、线程的开销

    1,空间上的开销

    ①线程内核数据结构,其中有osid,线程上下文(包含CPU寄存器集合的内存块)

    ②TEB(线程环境块)

    ③用户模式堆栈(默认分配1M空间)。会放参数、局部变量..

    ④内核模式堆栈(系统底层级别的堆栈空间)

    2,时间上的开销

    ①进程启动时会加载很多的dll(托管和非托管)。当线程开启或销毁时,会标记所有非托管dll

    ②时间片切换。当开启的线程多余系统线程数时,会发生时间片切换(时间片切换休眠时间为30ms)

    三、线程的生命周期

    Start:线程开启

    Suspend:线程暂停

    Resume:恢复暂停的线程

    Intterupt:中断线程(会抛出异常)

    Abort:销毁线程(会抛出异常)

    Join:等待线程执行完毕

    四、工作线程和IO线程

    工作线程:给一般的异步任务执行。其中不涉及到网络、文件这些IO 【开发者调用】

    IO线程:一般用在文件、网络IO上【CLR调用】

    五、Task

    Task=Thread(控制能力)+ThreadPool (在此基础上封装)

    Thread:容易造成时间+空间的浪费。控制能力可以

    ThreadPool :性能好,控制能力弱(控制权在CLR)。比如控制Thread超时、阻塞、取消等

    1,Task的三种启动方式

    Task底层都是由不同的TaskScheduler支撑(TaskScheduler相当于Task的CPU处理器)

    默认TaskScheduler是ThreadPoolTaskScheduler

    六、任务调度器

    任务都需要经过TaskScheduler

    1,ThreadPoolTaskScheduler(task默认调用此TaskScheduler)

     这个方式底层如果标记为LongRunning则使用Thread。否则调用ThreadPool

    2,SynchronizationContextTaskScheduler(同步上下文TaskScheduler)

    案例:

            private void button1_Click(object sender, EventArgs e)
            {
                new TaskFactory().StartNew(() =>
                {
                    //耗时的操作
                    Thread.Sleep(3000);
                }).ContinueWith(t =>
                {
                    label1.Text = "执行完成";
                }, TaskScheduler.FromCurrentSynchronizationContext());
            }

    七、多线程模型

    1,同步编程模型(SPM)

    2,异步编程模型(APM)

    xxxbegin

    xxxend

    委托给线程池执行的。FileStream(BeginRead,EndRead)配对方法、Action委托,都可以异步执行

    3,基于事件的编程模型(EAP)

    xxxAsync这样的事件模型。WebClient

    4,基于Task的编程模型(TAP)

    微软大力推广。APM和EAP都能包装成Task使用

            static void Main(string[] args)
            {
                Console.WriteLine("主线程。线程id:{0}", Thread.CurrentThread.ManagedThreadId);
    
                //异步编程模型(APM)包装成Task
                var action = new Action(() => { Console.WriteLine("执行Action。线程id:{0}", Thread.CurrentThread.ManagedThreadId); });
                var task = Task.Factory.FromAsync(action.BeginInvoke, action.EndInvoke, string.Empty);
    
    
    
                //基于事件的编程模型(EAP)包装成Task
                TaskCompletionSource<int> source = new TaskCompletionSource<int>();
                WebClient web = new WebClient();
                web.DownloadDataCompleted += (obj, e) => {
                    try
                    {
                        source.TrySetResult(e.Result.Length);
                    }
                    catch (Exception ex)
                    {
                        source.TrySetException(ex);
                    }
                };
                web.DownloadDataAsync(new Uri("https://www.oyunkeji.com"));
                Console.WriteLine(source.Task.Result);
    
    
                Console.ReadKey();
            }

    八、锁机制

    1,用户模式锁

    就是通过一些cpu指令或者一个死循环达到thread等待和休眠

    ①易变结构 volatile

    阻止cpu缓存,实时从内存中读取变量的值

    private static volatile bool isStop= false;

    ②互锁结构 Interlocked

    ③旋转锁 SpinLock

            public static SpinLock spinLock = new SpinLock();
            static int nums = 0;
            static void Run()
            {
                for (int i = 0; i < 10; i++)
                {
                    try
                    {
                        bool b = false;
                        spinLock.Enter(ref b);
                        Console.WriteLine(nums++);
                    }
                    catch (Exception ex)
                    {
                        spinLock.Exit();
                    }
                   
                }
            }
    
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Console.ReadKey();
            }
    SpinLock

    2,内核模式锁

    调用win32底层代码,来实现thread的各种操作

    万不得已的情况下,不要使用内核模式锁,代价太大

    ①自动事件锁

    场景:使用火车票进闸机,一人一人进

    namespace ConsoleApp1
    {
        class Program
        {
            private static AutoResetEvent areLock = new AutoResetEvent(true);
            static int nums = 0;
            static void Run()
            {
                for (int i = 0; i < 10; i++)
                {
                    areLock.WaitOne();
                    Console.WriteLine(nums++);
                    areLock.Set();
                }
            }
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Console.ReadKey();
            }
        }
    AutoResetEvent

    ②手动事件锁

    场景:栅栏阻挡行人、车辆等。适合批量

        class Program
        {
            private static ManualResetEvent mrLock = new ManualResetEvent(false);
            static int nums = 0;
            static void Run()
            {
                for (int i = 0; i < 10; i++)
                {
                    mrLock.WaitOne();//等待5秒后才会执行。拦一批值
                    Console.WriteLine(nums++);
                }
            }
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Thread.Sleep(5000);
                mrLock.Set();
    
                Console.ReadKey();
            }
        }
    ManualResetEvent

    ③信号量

    场景:传入允许线程的数量

        class Program
        {
            private static Semaphore sLock = new Semaphore(1, 1);
            static int nums = 0;
            static void Run()
            {
                for (int i = 0; i < 10; i++)
                {
                    sLock.WaitOne();
                    Console.WriteLine(nums++);
                    sLock.Release();
                }
            }
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Thread.Sleep(5000);
    
                Console.ReadKey();
            }
        }
    Semaphore

    ④互斥锁 

        class Program
        {
            private static Mutex mLock = new Mutex();
            static int nums = 0;
            static void Run()
            {
                for (int i = 0; i < 10; i++)
                {
                    mLock.WaitOne();
                    Console.WriteLine(nums++);
                    mLock.ReleaseMutex();
                }
            }
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Thread.Sleep(5000);
    
                Console.ReadKey();
            }
        }
    Mutex

    这四种锁都有一个WaitOne方法,因为他们都继承WaitHandle,这四种锁本是同根生,底层都是通过SafeWaitHandle来对win32api的一个引用

    ⑤读写锁

    如果写入线程时间太久,比如10s。这个时候读的线程会被卡死。从而超时

        class Program
        {
    
            private static ReaderWriterLock rwLock = new ReaderWriterLock();
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        Read();
                    });
                }
    
                Task.Factory.StartNew(() =>
                {
                    Write();
                });
    
                Console.ReadKey();
            }
    
            static void Read()
            {
                while (true)
                {
                    rwLock.AcquireReaderLock(int.MaxValue);
                    Thread.Sleep(100);
                    Console.WriteLine("read {0}", Thread.CurrentThread.ManagedThreadId);
                    rwLock.ReleaseReaderLock();
                }
            }
            static void Write()
            {
                while (true)
                {
                    Thread.Sleep(3000);
                    rwLock.AcquireWriterLock(int.MaxValue);
                    Thread.Sleep(3000);
                    Console.WriteLine("write {0}", Thread.CurrentThread.ManagedThreadId);
                    rwLock.ReleaseWriterLock();
                }
            }
        }
    ReaderWriterLock

    ⑥监视锁

        class Program
        {
    
            private static object objLock = new object();
            static void Main(string[] args)
            {
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
                Console.ReadKey();
            }
    
            static int nums = 0;
            private static void Run() {
    
                for (int i = 0; i < 100; i++)
                {
                    var b = false;
                    try
                    {
                        Monitor.Enter(objLock, ref b);
                        Console.WriteLine(nums++);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        if (b) Monitor.Exit(objLock);
                    }
                }
            }
           
        }
    lock

    3,混合锁

    用户模式+内核模式(场景是最多的)

    在用户模式下内旋,如果超过一定的阔值,会切换到内核锁。在内旋的情况下,我们会看到大量的Sleep(0)、Sleep(1)、Yield等

    ①ManualResetEventSlim

        class Program
        {
    
            private static ManualResetEventSlim mrsLock = new ManualResetEventSlim();
            static void Main(string[] args)
            {
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
    
                Thread.Sleep(1000);
                mrsLock.Set();
                Console.ReadKey();
            }
    
            static int nums = 0;
            private static void Run()
            {
                for (int i = 0; i < 1000; i++)
                {
                    mrsLock.Wait();//等待1秒后才会执行。拦一批值
                    Console.WriteLine(nums++);
                }
            }
           
        }
    ManualResetEventSlim

    ②SemaphoreSlim

        class Program
        {
    
            private static SemaphoreSlim mrsLock = new SemaphoreSlim(1,10);
            static void Main(string[] args)
            {
                for (int i = 0; i < 5; i++)
                {
                    Task.Run(() =>
                    {
                        Run();
                    });
                }
    
                Console.ReadKey();
            }
    
            static int nums = 0;
            private static void Run()
            {
                for (int i = 0; i < 1000; i++)
                {
                    mrsLock.Wait();
                    Console.WriteLine(nums++);
                    mrsLock.Release();
                }
            }
           
        }
    SemaphoreSlim

    ③ReaderWriterLockSlim

        class Program
        {
    
            private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
            static void Main(string[] args)
            {
    
                for (int i = 0; i < 5; i++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        Read();
                    });
                }
    
                Task.Factory.StartNew(() =>
                {
                    Write();
                });
    
                Console.ReadKey();
            }
    
            static void Read()
            {
                while (true)
                {
                    rwLock.EnterReadLock();
                    Thread.Sleep(100);
                    Console.WriteLine("read {0}", Thread.CurrentThread.ManagedThreadId);
                    rwLock.ExitReadLock();
                }
            }
            static void Write()
            {
                while (true)
                {
                    Thread.Sleep(3000);
                    rwLock.EnterWriteLock();
                    Thread.Sleep(3000);
                    Console.WriteLine("write {0}", Thread.CurrentThread.ManagedThreadId);
                    rwLock.ExitWriteLock();
                }
            }
        }
    ReaderWriterLockSlim
  • 相关阅读:
    楼宇监控说明
    数字音视频监控系统说明
    图书管理系统详细设计说明
    超邃视频远程监控系统说明
    单点登录系统(SSO)详细设计说明
    视频监控系统的作用何在
    视频监控技术与应用
    HTML--CSS样式表--基本概念(超链接的状态)
    HTML静态网页--框架
    HTML--表格与表单
  • 原文地址:https://www.cnblogs.com/zd1994/p/8262222.html
Copyright © 2020-2023  润新知