golang mutex(互斥锁)
1.锁最本质的作用
保证原子性
2.mutex 使用原则
适用于并发编程,尽量减少加锁区域的逻辑
3.mutex的局限性
仅限于单个进程内操作
sema(信号量,semaphore的简称)是一种用于并发控制的机制
资源计数:信号量维护一个资源计数。这个计数表示当前可用的资源数量
获取操作(P操作):当一个协程(goroutine)想要获取资源时,会检查信号量的资源计数,如果计数大于0,说明有可用资源,协程可以获取资源,同时信号量的计数减1;如果计数为0,表示没有可用资源,协程就会阻塞等待,直到有其他协程释放资源
释放操作(V操作):当一个协程使用完资源后,会释放资源。这会使信号量的计数加1,如果有协程正在等待这个资源,那么其中一个等待的协程会被唤醒并获取到资源
锁分快慢两种获取路径
互斥锁可以处于两种操作模式:正常模式和饥饿模式
在正常模式下,等待者按照先进先出(FIFO)的顺序排队,但是被唤醒的等待者并不拥有互斥锁,并且要与新到达的协程竞争互斥锁的所有权。
新到达的协程具有优势--它们已经在CPU 上运行,而且可能教量众多,所以被唤醒的等待者很有可能竞争失败,在这种情况下,它会被排到等待队列的前端,如果一个等待者超过1毫秒未能获取到互斥锁,它就会将互斥锁切换到饥饿模式。
在饥饿模式下,互斥锁的所有权直接从解锁的协程传递给队列前端的等待者。新到达的协程即使看到互斥锁似乎未被锁定也不会尝试获取,也不会尝试空转(自旋),相反,它们会将自己排到等待队列的末尾。
如果一个等待者获得了互斥锁并且发现:
(1)它是队列中的最后一个等待者
(2)它的等待时间少于1毫秒
它就会将互斥锁切换回正常操作模式。
golang RMmutex(读写锁)
1.读写锁与互斥锁的区别
互斥锁:同一时间只允许持锁的协程访问被保护的资源,不论读写
读写锁:在互斥锁的基础上进行了优化,将操作分为读操作和写操作,允许多个协程同时进行读操作。但写操作必须独占访问,从而提高读多写少场景下的并发性能
2.读写锁的应用场景
读多写少的应用场景,比如:缓存,配置等操作
3.读写锁的底层实现
type RWMutex struct {w Mutex // held if there are pending writerswriterSem uint32 // 用于writer等待读完成排队的信号量readerSem uint32 // 用于reader等待写完成排队的信号量readerCount int32 // 读锁的计数器readerWait int32 // 等待读锁释放的数量
}
参考:https://blog.csdn.net/qq_41035588/article/details/108633171