你的位置:首页 > 软件开发 > ASP.net > 【C#进阶系列】28 基元线程同步构造

【C#进阶系列】28 基元线程同步构造

发布时间:2016-05-24 02:00:05
多个线程同时访问共享数据时,线程同步能防止数据损坏。之所以要强调同时,是因为线程同步问题实际上就是计时问题。不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗漏,而且锁会损耗性能,获取和释放锁都需要时间,最后锁的玩法就在于一次只能让一个线程 ...

多个get='_blank'>线程同时访问共享数据时,线程同步能防止数据损坏。之所以要强调同时,是因为线程同步问题实际上就是计时问题。

不需要线程同步是最理想的情况,因为线程同步一般很繁琐,涉及到线程同步锁的获取和释放,容易遗漏,而且锁会损耗性能,获取和释放锁都需要时间,最后锁的玩法就在于一次只能让一个线程访问数据,那么就会阻塞线程,阻塞线程就会让额外的线程产生,阻塞越多,线程越多,线程过多的坏处就不谈了。

所以可以避免线程同步的话就应该去避免,尽量不要去使用静态字段这样的共享数据。

类库和线程安全

.net类库保证了所有静态方法都是线程安全的,也就是说两个线程同时调用一个静态方法,不会发生数据被破坏的情况。

并不能保证所有实例方法线程安全。因为一般情况下实例创建后只有创建的线程能访问到,除非后来将实例的引用传给了一个静态变量,或者将引用传给了线程池的队列或者任务,那么此时可能就要考虑用线程同步了。

Console类包含一个静态字段,类的许多方法都要获取和释放这个对象上的锁,确保只有一个线程访问控制台。

基元用户模式和内核模式构造(这一部分看不明白可以先看看后面的用户模式和内核模式的讲解,就会清楚了)

基元是指可以在代码中使用的最简单的构造。

有两种基元构造:用户模式和内核模式。应尽量使用基元用户模式构造,它们的速度显著高于内核模式的构造。

这是因为它们使用特殊的CPU指令来协调线程,意味着协调是在硬件上发生的,也意味着操作系统永远检测不到一个线程在基元用户模式的构造上阻塞了。

只有操作系统内核才能停止一个线程的运行。

所以在用户模式下运行的线程可能被系统抢占。

所以也可以用内核模式构造,因为线程通过内核模式的构造获取其它线程拥有的资源时,Windows会阻塞线程以避免它浪费CPU时间。当资源变得可用时,Windows会恢复线程,允许它访问资源。

然而线程从用户模式切换到内核模式(或相反)会招致巨大的性能损失。

对于在一个构造上等待的线程,如果占有构造的这个线程不释放它,前者就可能一直阻塞。构造是用户模式的构造情况下,线程会一直在一个CPU上运行,称为“活锁”。如果是内核模式的构造,线程会一直阻塞,称为“死锁”。

死锁优于活锁,因为活锁既浪费CPU时间,又浪费内存,而死锁只浪费内存。

而混合构造兼具两者之长,在没有竞争的情况下,这个构造很快且不会阻塞(就像用户模式的构造),在存在对构造的竞争的情况下,它会**作系统内核阻塞。(下一章讲)

用户模式构造

CLR保证对以下数据类型的变量的读写是原子性的:Boolean,Char,S(Byte),U(Int16),U(Int32),U(IntPtr),Single以及引用类型。

这意味着变量中的所有字节都是一次性读取或写入。(举个反例,对于一个Int64静态变量初始化为0,一个线程写它的时候只写了一半,另一个线程读取的时候读取到的是中间状态。不过话说回来,貌似64位机器一次性读取64位,是不是在这个时候Int64也会编程原子性呢,未验证,不过不影响我们理解。)

本章讲解的基元用户模式构造就在于规划好这些原子性数据的读取/写入时间。

实际上这些构造也可以强制为Int32和Double这些类型数据进行原子性的规划好时间的访问。

有两种基元用户模式线程同步构造

  • 易变构造
  • 互锁构造

所有易变和互锁构造都要求传递对包含简单数据类型的一个变量的引用(内存地址)。

易变构造

在讲易变构造之前,得先讲一个问题,就是代码优化的问题。

之前我们讲过C#编译器,JIT编译器,CPU都可能会优化代码,典型的例子就是Timer的应用,一个Timer对象在后续没有使用的情况下,可能直接被优化掉了,根本不会定时执行回调函数。

而这些优化效果是很难在调试的时候看出来,因为调试的时候并没有对代码进行优化。

多线程也会导致这样的问题,比如一个线程回调函数用到某个静态变量后,且并不改变这个变量,那么可能就会进行优化,认为这个变量的值不变,让其直接优化成固定的值。而你本来的目的实在另一个线程中改变这个静态变量的值,现在你的改变也起不了效果看了。

并且以下这样的代码而言可能因为代码的执行顺序不同而出现超出预料的结果。

    static int you = 0;    static int me = 0;    private static void Thread1() {      me = 2;      you = 2;    }    private static void Thread2()    {      if (you == 2) {        Console.WriteLine(me);          }  

 

海外公司注册、海外银行开户、跨境平台代入驻、VAT、EPR等知识和在线办理:https://www.xlkjsw.com

原标题:【C#进阶系列】28 基元线程同步构造

关键词:C#

C#
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

可能感兴趣文章

我的浏览记录