深入理解.Net中的线程同步之构造模式(一)用户模式构造

  • 两种构造模式
    有两种基元构造:用户模式(user-mode)和内核模式( kernel-mode)。应尽量使用基元用户模式构造,它们的速度要显著快于内核模式的构造。为什么用户模式要快于内核模式呢?这是因为它们使用了特殊CPU指令来协调线程。这意味着协调是在硬件中发生的(所以才这么快)。
    换句话说用户模式不是没有阻塞而是阻塞的很短,在硬件层面,对于内核系统来说,他不知道发生了阻塞,所有认为永远不会阻塞。而内核模式就是系统帮我们虚拟出的一个构造,它相比用户构造虽然性能不好,会阻塞但是不会占着cpu一直跑。就像我们while(true)时 ,会让线程睡一会,来让其他线程用一下cpu
  • 这2种构造模式各有优缺点,将他们组合一下,出行了第三种模式,混合构造hybrid construct,混合构造就能很快的调用又能不浪费cpu的算力。
  • window下的用户模式构造

  • 易变构造
    易变构造就是说对一个数据的操作是非原子性的,数据可能滞留在cpu缓存中,从而造成数据的脏读脏写(根据数据库脏读而来),如何易变构造呢?
    将变量用volatile修饰,可以保证变量的原子性
    volatile可以修饰Boolean,(S)Byte,(U)Int16,(U)Int32,(U)IntPtr, Single和 Char类型
        public volatile int int_a;
        public volatile char char_a;

使用volatile请注意,不要滥用volatile,可能会造成编译器放弃优化部分代码而造成性能损失。
当如下情况 可能会造成一定性能损失,编译时选择优化代码,首选32位系统

    internal class vol_Test
    {
        public volatile int int_a;
        public volatile char char_a;
        public int int_b;

        public int int_c;

        public void TestStart()
        {
            for (int i = 0; i < 10; i++) {

                {
                    B_Add();
                    A_Add();
           
                }
       
            }
         
        }

        public void A_Add()
        {
            System.Diagnostics.Stopwatch oTime = new System.Diagnostics.Stopwatch();   //定义一个计时对象  
            oTime.Start();                         //开始计时 
            for (int i = 0; i < 100000000; i++)
            {
                int_a = 1;
                for (int j = 0; j < 30; j++)
                {
               
                    int_a +=int_a;
    
                }
           
            }
            oTime.Stop();
            Console.WriteLine($"AAAAAAAAAAAAA A_Add {int_a} 程序的运行时间:{oTime.Elapsed.TotalSeconds}{oTime.Elapsed.TotalMilliseconds} 毫秒");

        }
        public void B_Add()
        {
            System.Diagnostics.Stopwatch oTime = new System.Diagnostics.Stopwatch();   //定义一个计时对象  
            oTime.Start();                         //开始计时 
            for (int i = 0; i < 100000000; i++)
            {
                int_b = 1;
                for (int j = 0; j < 30; j++)
                {
           
                    int_b += int_b;
             
                }
                    
            }
            oTime.Stop();
            Console.WriteLine($"B_Add {int_b}  程序的运行时间:{oTime.Elapsed.TotalSeconds}{oTime.Elapsed.TotalMilliseconds} 毫秒");

        }
    }

运行结果
其实很难看出volatile 变量和普通变量的差别,只能说从理论上来说volatile 变量的性能可能略次于普通变量
在这里插入图片描述

  • 互锁构造
    互锁构造主要是对Interlocked的使用,Interlocked类中方法都是原子的
    在这里插入图片描述

也就是说,Interlocked add 或者read一个int数据的时候,是一定不会产生脏读的
利用Interlocked的特性,我们可以实现一个简单的自旋锁

public struct SimpleSpinLock{
    private int m_Lock;

    public void Enter(){
        while (true){
            if (Interlocked.Exchange(ref m_Lock, 1) == 0) return;
        }
    }

    public void Leave(){
        Volatile.Write(ref m_Lock, 0);
    }
}

//下面是如何使用SimpleSpinLock的例子
public class Simple{
    private SimpleSpinLock m_lock = new SimpleSpinLock();

    public void AccessResource(){
        m_lock.Enter();
        //执行某些程序,只有一个线程可以进入这里
        m_lock.Leave();
    }
}

事件的代码中,如此使用自旋锁虽然性能很好,但是会大量的占用cpu时间,所以,仅仅是自旋还是不够的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值