• .NET同步与异步之相关背景知识(六)


    在之前的五篇随笔中,已经介绍了.NET 类库中实现并行的常见方式及其基本用法,当然、这些基本用法远远不能覆盖所有,也只能作为一个引子出现在这里。以下是前五篇随笔的目录:

    .NET 同步与异步之封装成Task(五)

    .NET 实现并行的几种方式(四)

    .NET 实现并行的几种方式(三)

    .NET 实现并行的几种方式(二)

    .NET 实现并行的几种方式(一)

    话再说回来,这五篇随笔都属于《同步与异步》系列。同步与异步、这是一个很大、很笼统的话题,以笔者所学很难将其将其介绍清楚,不过、笔者还是会尽力的。以下是笔者打算在近期介绍的一些知识点(大纲)、当然如果您有更好的意见或建议、欢迎评论留言。

    1、与“同步与异步”相关的一些背景知识(即当前随笔)

      线程上下文、上下文切换、竞争条件(竞态条件)、锁、死锁。

    2、锁(Lock、Monitor、ReaderWriterLockSlim)(预计1-2篇随笔)

    3、原子操作和自旋锁(Interlocked、SpinLock)(预计1篇随笔)

    https://msdn.microsoft.com/zh-cn/library/system.threading.spinlock(v=vs.110).aspx

    https://msdn.microsoft.com/zh-cn/library/system.threading.interlocked(v=vs.110).aspx

    4、WaitHandle家族 (预计2篇随笔)

    https://msdn.microsoft.com/zh-cn/library/system.threading.waithandle(VS.80).aspx

    https://msdn.microsoft.com/zh-cn/library/system.threading.semaphoreslim(v=vs.110).aspx

    5、警惕闭包中的变量捕获(预计1篇随笔)

    6、线程安全的集合(预计1篇随笔)



    好了,大纲暂时就先这些了,下面进入该篇随笔的正文、线程方面的相关背景知识:

    线程上下文

    线程的强大之处、我就不再强调了。如此强大的线程、想要“免费”使用它,似乎是不可能的,就像有句话说的那样:出来混总是要还的。

    Windows中每开辟一个线程、系统都要默认分配一定量的内存空间、其中有一块内存空间用来保存CPU寄存器中的值,我们把这个内存块称为线程上下文。

    内存空间中除了寄存器集合之外,还有一部分叫线程栈,线程栈的内存开销要比寄存器集合的内存开销大的多。

    上下文切换

    线程、是程序执行流的最小单元,它就像一个逻辑CPU(或者虚拟CPU)。在系统中多个逻辑CPU(线程)共享计算机中的物理CPU核心(一个CPU可能有多个核心)。

    Windows在任何时刻,都只会把一个线程分配给一个CPU核心去运行。被分配的线程运行一个“时间片”长度后,时间片到期,此时Windows会切换上下文。

    每次切换上下文,Windows都会做如下操作:

    1、将CPU寄存器中的值保存到当前的线程上下文中。2、从现有的线程集合中挑选一个线程。3、将挑选的线程的上下文加载到CPU寄存器中。

    上下文切换完成后,CPU会运行所选线程,直到它的时间片到期,然后再次发生上下文切换。Windows大约会30毫秒切换一次线程上下文。

    事实上、上下文切换对性能的影响可能超乎了你的想象:

    线程在运行时,线程所需的代码和数据都存放在CPU的高速缓存中,这使得CPU不必经常访问内存RAM(访问它的速度要比访问高速缓存的速度慢的多)。

    当Windows进行上下文切换后、线程运行所需的代码和数据,可能不在CPU的高速缓存中,因此CPU必须访问RAM来填充高速缓存、以恢复CPU的高速运行。

    但是,大约30毫秒后,上下文切换再一次发生了。

    另外、当一个时间片结束后,如果Widnows决定继续运行同一个线程,那么将不发生上下文切换。

    线程也可以自主终止其时间片,节省出来的时间、CPU可以用来运行其他线程。

    关于 Thread.Sleep   方法、这里说一下它的三个特殊参数, -1, 0, 1 毫秒。

    -1,当前线程将永远休眠(此参数其实没有意义,虽然Windows不再调度该线程,但它还是占用着内存)。

    0,当前线程放弃了剩余的时间片,促使Windows发生上下文切换。当然此时Windows有可能还会继续运行当前休眠的线程(没有相同和更高优先级的线程需要运行的时候)

    1,Sleep(0), 是不允许线程优先级较低的线程运行的, 而 Sleep(1) 会强制发生一次上下文切换。

     

    竞争条件

    假如有以下一行代码、假定当时 整形变量i的值为 0 :

    i = i + 1;

    当有两个线程同时运行该行代码后,变量i的值变为了1。这时候的结果和预期的值2不一致,这时候我们认为是由于竞争条件引发了安全问题。

    引发该问题的原因是:多个线程同时访问了共享资源。

    存在竞争条件的代码,我们认为是线程不安全的代码。

    锁 和 死锁

    解决竞争条件的典型方案是,获取共享资源的独占式访问特权,而获取该特权的过程、我们称之为加锁。而这个特权、就是锁。

    但是、加锁和释放锁的过程中开销较大、性能影响较大。还有一类更好的解决方案:原子操作,我有时候也会把它称为轻量级锁。

    当两把锁相互等待对方释放的时候、我们认为此时发生了死锁。

    随笔暂告一段落、下一篇随笔介绍: 锁(Lock、Monitor、ReaderWriterLockSlim)(预计1-2篇随笔)

    附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

    参见更多:随笔导读:同步与异步


    (未完待续...)

  • 相关阅读:
    cholesky分解
    LU分解(2)
    LU分解(1)
    自定义UITableView的Seperator
    iOS屏蔽高频点击技巧
    iOS动态管理AutoLayout的约束NSLayoutConstraint
    Reachability几个常用方法
    XCode4 下制作Framework的方法
    StoryBoard 的使用
    Objective-C RunTime
  • 原文地址:https://www.cnblogs.com/08shiyan/p/6168995.html
Copyright © 2020-2023  润新知