视频结构可视化平台EasyNVR拉转推视频流场景中采用互斥锁sync.Mutex和读写互斥锁sync.RWMutex的区别

2021-04-19 16:53:36 浏览数 (1)

在EasyNVR视频平台使用的视频直播项目场景中,经常会有多路推拉流的场景出现,因为基本是采用异步调用的方式,所以在多并发的情况下会出现数据不安全问题,这个时候就需要使用锁,来进行协程数据安全的处理。

Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。Mutex为互斥锁,适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景;RWMutex是一个读写锁,该锁可以加多个读锁或者一个写锁,其经常用于读次数远远多于写次数的场景。

sync.Mutex 锁

该锁的结构体定义如下:

代码语言:javascript复制
// A Mutex is a mutual exclusion lock.
// The zero value for a Mutex is an unlocked mutex.
//
// A Mutex must not be copied after first use.
type Mutex struct {
   state int32
   sema  uint32
}

该结构体主要实现了 Locker 接口,对外部暴露两个方法Lock() 和 Unlock()

代码语言:javascript复制
// A Locker represents an object that can be locked and unlocked.
type Locker interface {
   Lock()
   Unlock()
}

该种锁的特点是,一旦 Lock() 锁定,其他所有协程都不能访问对应的数据,除非该协程调用 Unlock() 将锁释放出来。

在实际编码使用中,很少使用 sync.Mutex 锁,该种锁使用其他比较粗暴,为考虑读写的场景,在很多场景中,经常会有该种需求,一份数据在被读取的时候,其他协程也可以读取,但是一份数据在被写入新的数据时,不允许其他协程读写,因此又出现了 sync. RWMutex 这种读写锁的出现。读写锁,在实际使用中更高效。

sync. RWMutex锁

代码语言:javascript复制
type RWMutex struct {
   w           Mutex  // held if there are pending writers
   writerSem   uint32 // semaphore for writers to wait for completing readers
   readerSem   uint32 // semaphore for readers to wait for completing writers
   readerCount int32  // number of pending readers
   readerWait  int32  // number of departing readers
}

读写锁也是依靠 sync.Mutex 这种锁来进行,该锁主要提供 RLock()、URLock()、Lock()和Unlock() 四个方法来。读锁为 RLock()方法,写锁为 Lock() 方法。其中对于读锁,不允许递归调用。以下是读锁的使用方式:

代码语言:javascript复制
func (rw *RWMutex) RLock() {
   if race.Enabled {
      _ = rw.w.state
      race.Disable()
   }
   if atomic.AddInt32(&rw.readerCount, 1) < 0 {
      // A writer is pending, wait for it.
      runtime_SemacquireMutex(&rw.readerSem, false, 0)
   }
   if race.Enabled {
      race.Enable()
      race.Acquire(unsafe.Pointer(&rw.readerSem))
   }
}

sync 包中还提供了一些 sync.Map 和 sync.WaitGroup 等试用的结构体,在遇见对应的场景下再进行介绍。

0 人点赞