.NET中各种线程同步锁
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
编程编的久了,总会遇到多线程的情况,有些时候我们要几个线程合作完成某些功能,这时候可以定义一个全局对象,各个线程根据这个对象的状态来协同工作,这就是基本的 支持多线程编程的语言一般都内置了一些类型和方法用于创建上述所说的全局对象也就是 ps:本文虽然关注 .Net 平台,但涉及到的大部分锁概念都是平台无关的,在很多其它语言(如_ volatile 关键字#确切地说, 缓存一致性#了解 我们知道,在现代计算机中,处理器的指令速度远超内存的存取速度,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存来作为主存与处理器之间的缓冲。处理器计算直接存取的是高速缓存中的数据,计算完毕后再同步到主存中。 在多处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一主存。 而 Java 内存模型的每个线程有自己的工作内存,其中保留了被线程使用的变量的副本。线程对变量的所有的操作都必须在工作内存中完成,而不能直接读写主内存中的变量。不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存中转来完成。 虽然两者的设计相似,但是前者主要解决存取效率不匹配的问题,而后者主要解决内存安全(竞争、泄露)方面的问题。显而易见,这种设计方案引入了新的问题—— 为了解决这个问题,很多平台都内置了 volatile 关键字,使用它修饰的变量,可以保证所有线程每次获取到的是最新值。这是怎么做到的呢?这就要求所有线程在访问变量时遵循预定的协议,比如 另外 volatile 还能避免编译器自作聪明重排指令。重排指令在大多数时候无伤大雅,还能对执行效率有一定提升,但某些时候会影响到执行结果,此时就可以使用 volatile。 Interlocked#同 volatile 的 它的原子操作基于 CPU 本身,非阻塞,所以也不是真正意义上的锁,当然效率会比锁高得多。 锁模式#接下来正式介绍各种锁之前,先了解下锁模式——锁分为 内核模式就是在系统级别让线程中断,收到信号时再切回来继续干活。该模式在线程挂起时由系统底层负责,几乎不占用 CPU 资源,但线程切换时效率低。 用户模式就是通过一些 CPU 指令或者死循环让线程一直运行着直到可用。该模式下,线程挂起会一直占用 CPU 资源,但线程切换非常快。 长时间的锁定,优先使用内核模式锁;如果有大量的锁定,且锁定时间非常短,切换频繁,用户模式锁就很有用。另外内核模式锁可以实现跨进程同步,而用户模式锁只能进程内同步。 本文中,除文末 lock 关键字#
Monitor#上面 lock 就是
Monitor 还可以设置超时时间,避免无限制的等待。同时它还有 ReaderWriterLock#很多时候,对资源的读操作频率要远远高于写操作频率,这种情况下,应该对读写应用不同的锁,使得在没有写锁时,可以并发读(加读锁),在没有读锁或写锁时,才可以写(加写锁)。 主要的特点是在没有写锁时,可以并发读,而非一概而论,不论读写都只能一次一个线程。 MethodImpl(MethodImplOptions.Synchronized)#如果是方法层面的线程同步,除上述的 SynchronizationAttribute#ContextBoundObject#要了解 首先进程中承载程序集运行的逻辑分区我们称之为 在上下文的接口当中存在着一个消息接收器负责检测拦截和处理信息。当对象是 而 ps: 相对的,没有继承自 ContextBoundObjec t的类的实例则被视为 一个进程内可以包括多个应用程序域,也可以有多个线程。线程可以穿梭于多个应用程序域当中,但在同一个时刻,线程只会处于一个应用程序域内。线程也能穿梭于多个上下文当中,进行对象的调用。
WaitHandle#在查阅一些异步框架的源码或接口时,经常能看到 WaitHandle 包含有以下几个派生类:
ManualResetEvent#可以阻塞一个或多个线程,直到收到一个信号告诉 ManualResetEvent 不要再阻塞当前的线程。 注意所有等待的线程都会被唤醒。 可以想象 ManualResetEvent 这个对象内部有一个信号状态来控制是否要阻塞当前线程,有信号不阻塞,无信号则阻塞。这个信号我们在初始化的时候可以设置它,如 代码举例:
AutoResetEvent#用法上和 ManualResetEvent 差不多,不再赘述,区别在于内在逻辑。 与 ManualResetEvent 不同的是,当某个线程调用Set方法时,只有一个等待的线程会被唤醒,并被允许继续执行。如果有多个线程等待,那么只会随机唤醒其中一个,其它线程仍然处于等待状态。 另一个不同点,也是为什么取名 CountdownEvent#它的信号有计数状态,可递增 注意:CountdownEvent 是用户模式锁。 Mutex#Mutex 这个对象比较“专制”,同时段内只能准许一个线程工作。 Semaphore#对比 Mutex 同时只有一个线程工作, 轻量级同步#.NET Framework 4 开始,System.Threading 命名空间中提供了六个新的数据结构,这些数据结构允许细粒度的并发和并行化,并且降低一定必要的开销,它们称为轻量级同步原语,它们都是用户模式锁,包括:
Barrier#当在需要一组任务并行地运行一连串的阶段,但是每一个阶段都要等待其他任务完成前一阶段之后才能开始时,您可以通过使用 SpinWait#如果等待某个条件满足需要的时间很短,而且不希望发生昂贵的上下文切换,那么基于自旋的等待时一种很好的替换方案。 需要注意的是:长时间的自旋不是很好的做法,因为自旋会阻塞更高级的线程及其相关的任务,还会阻塞垃圾回收机制。SpinWait 并没有设计为让多个任务或线程并发使用,因此需要的话,每一个任务或线程都应该使用自己的 SpinWait 实例。 当一个线程自旋时,会将一个内核放入到一个繁忙的循环中,而不会让出当前处理器时间片剩余部分,当一个任务或者线程调用 因此,在大部分情况下, 不要在循环内调用 Thread.Sleep 方法等待特定的条件满足 。
转自https://www.cnblogs.com/newton/p/18365359 该文章在 2024/8/19 8:31:40 编辑过 |
关键字查询
相关文章
|