多线程学习笔记

 一、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

 

转载于:https://www.cnblogs.com/zd1994/p/8262222.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值