critical的用法归纳 criticalsection函数怎么使用( 二 )


在使用锁时需要明确几个问题:
锁的所有权问题 谁加锁 谁解锁 解铃还须系铃人锁的作用就是对临界区资源的读写操作的安全限制锁是否可以被多个使用者占用(互不影响的使用者对资源的占用)占用资源的加锁者的释放问题 (锁持有的超时问题)等待资源的待加锁者的等待问题(如何通知到其他等着资源的使用者)多个临界区资源锁的循环问题(死锁场景)带着问题明确想要达到的目的,我们同样可以根据自己的需求设计锁,Linux现有的锁如果从上面几个问题的角度去理解,就非常容易了 。
需要C/C++ Linux服务器架构师学习资料加群812855908(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)
自旋锁spinlock自旋锁的主要特征是使用者在想要获得临界区执行权限时,如果临界区已经被加锁,那么自旋锁并不会阻塞睡眠,等待系统来主动唤醒,而是原地忙轮询资源是否被释放加锁,自旋就是自我旋转,这个名字还是很形象的 。
自旋锁有它的优点就是避免了系统的唤醒,自己来执行轮询,如果在临界区的资源代码非常短且是原子的,那么使用起来是非常方便的,避免了各种上下文切换,开销非常小,因此在内核的一些数据结构中自旋锁被广泛的使用 。
互斥锁mutex使用者使用互斥锁时在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作,谁加锁谁释放,其他使用者没有释放权限 。加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前进程解锁 。
区别于自旋锁,互斥锁无法获取锁时将阻塞睡眠,需要系统来唤醒,可以看出来自旋转自己原地旋转来确定锁被释放了,互斥锁由系统来唤醒,但是现实并不是那么美好的,因为很多业务逻辑系统是不知道的,仍然需要业务线程执行while来轮询是否可以重新加锁 。
考虑这种情况:解锁时有多个线程阻塞,那么所有该锁上的线程都被编程就绪状态,第一个变为就绪状态的线程又执行加锁操作,那么其他的线程又会进入等待,对其他线程而言就是虚假唤醒 。
在这种方式下,只有一个线程能够访问被互斥锁保护的资源 。
读写锁rwlock读写锁也叫共享互斥锁:读模式共享和写模式互斥,本质上这种非常合理,因为在数据没有被写的前提下,多个使用者读取时完全不需要加锁的 。
读写锁有读加锁状态、写加锁状态和不加锁状态三种状态,当读写锁在写加锁模式下,任何试图对这个锁进行加锁的线程都会被阻塞,直到写进程对其解锁 。
读优先的读写锁:
读写锁rwlock默认的也是读优先,也就是:当读写锁在读加锁模式先,任何线程都可以对其进行读加锁操作,但是所有试图进行写加锁操作的线程都会被阻塞,直到所有的读线程都解锁,因此读写锁很适合读次数远远大于写的情况 。这种情况需要考虑写饥饿问题,也就是大量的读一直轮不到写,因此需要设置公平的读写策略 。
在一次面试中曾经问到实现一个写优先级的读写锁,感兴趣的可以想想如何实现 。
RCU锁RCU锁是读写锁的扩展版本,简单来说就是支持多读多写同时加锁,多读没什么好说的,但是对于多写同时加锁,还是存在一些技术挑战的 。
RCU锁翻译为Read Copy Update Lock,读-拷贝-更新 锁 。
Copy拷贝:写者在访问临界区时,写者将先拷贝一个临界区副本,然后对副本进行修改;
Update更新:RCU机制将在在适当时机使用一个回调函数把指向原来临界区的指针重新指向新的被修改的临界区,锁机制中的垃圾收集器负责回调函数的调用 。


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: