天天看点

golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写

目录

1、临界资源访问存在的问题

2、使用WaitGroup等待一组线程的结束

3、互斥锁——处理临界资源中的并发问题

4、读写锁——多读一写

1、临界资源访问存在的问题

golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写

如上图所示,会出现多个窗口卖出同一张票以及卖出负票的问题

2、使用WaitGroup等待一组线程的结束

由于一旦主协程执行结束,即时其他协程还没有执行完成也会退出,上面例子我们强制在主协程中设置休眠时间,但是这样做不太好,而使用WaitGroup可以解决上述问题

WaitGroup用于等待一组线程的结束。父线程调用Add方法来设定应等待的线程的数量。每个被等待的线程在结束时应调用Done方法。同时,主线程里可以调用Wait方法阻塞至所有线程结束。
golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写

如上图所示,这样做的话即时主线程执行完了也不会退出,直到等待的线程数量变为0了才会退出

3、互斥锁——处理临界资源中的并发问题

保证在任何时候都只能有一个goroutine来访问资源,其他goroutine都等待

golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写

相对于第一部分的代码,改进了如下两个地方:

  • 加入了sync.Mutex互斥锁,解决了临界资源并发访问的问题
  • 加入了sync.WaitGroup,解决了主协程一结束其他子协程就被强制结束的问题

4、读写锁——多读一写

RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。

读写锁有如下四个方法:

  • 写操作的锁定和解锁分别是

    func (*RWMutex) Lock

    func (*RWMutex) Unlock

  • 读操作的锁定和解锁分别是

    func (*RWMutex) Rlock

    func (*RWMutex) RUnlock

读写锁的区别在于:

  • 当有一个 goroutine 获得写锁定,其它无论是读锁定还是写锁定都将阻塞直到写解锁;
  • 当有一个 goroutine 获得读锁定,其它读锁定仍然可以继续;
  • 当有一个或任意多个读锁定,写锁定将等待所有读锁定解锁之后才能够进行写锁定。

所以说这里的读锁定(RLock)目的其实是告诉写锁定,有很多协程或者进程正在读取数据,写操作需要等它们读(读解锁)完才能进行写(写锁定)。

我们可以将其总结为如下三条:

  • 同时只能有一个 goroutine 能够获得写锁定;
  • 同时可以有任意多个 gorouinte 获得读锁定;
  • 同时只能存在写锁定或读锁定(读和写互斥)。
golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写
golang的同步包sync解析——互斥锁/读写锁1、临界资源访问存在的问题2、使用WaitGroup等待一组线程的结束3、互斥锁——处理临界资源中的并发问题4、读写锁——多读一写