golang-锁问题1-5

1.说下Go中的锁有哪些?三种锁,互斥锁,读写锁,还有map的安全的锁?

互斥锁:同一时刻只能有一个协程获取这把锁,其他的只能等待
读写锁:依赖与互斥锁实现,多个协程可以同时获取读锁,读取资源不限制。但是同一时刻只能一个协程获取写锁
map安全锁:原生map是非并发安全的,所以为了保证map的并发安全,最简单的方式就是给map加锁。
sync.Map是加过锁的,可以直接安全使用

1.1互斥锁

var x int64
var wg sync.WaitGroup
var lock sync.Mutex

func add() {
    for i := 0; i < 5000; i++ {
        lock.Lock() // 加锁
        x = x + 1
        lock.Unlock() // 解锁
    }
    wg.Done()
}

func main() {
    wg.Add(2)
    go add()
    go add()
    wg.Wait()
    fmt.Println(x)
} 

1.2读写锁

var (
	x      int64
	wg     sync.WaitGroup
	rwlock sync.RWMutex
)

func write() {
	rwlock.Lock() // 加写锁
	x = x + 1
	time.Sleep(10 * time.Millisecond) // 假设读操作耗时10毫秒
	rwlock.Unlock()                   // 解写锁
	wg.Done()
}

func read() {
	rwlock.RLock()               // 加读锁
	time.Sleep(time.Millisecond) // 假设读操作耗时1毫秒
	rwlock.RUnlock()             // 解读锁
	wg.Done()
}
读写锁,可以同时获取多个读锁,但是只能同时获取一把写锁。
读写锁当有⼀个协程在等待写锁时,其他协程是不能获得读锁的,让写锁优先获取,⽽A 的读锁⼜要求C 调⽤完成,因此死锁。

var mu sync.RWMutex
var count int
func main() {
	go A()
	time.Sleep(2 * time.Second)
	mu.Lock()
	defer mu.Unlock()
	count++
	fmt.Println(count)
}
func A() {
	mu.RLock()
	defer mu.RUnlock()
	B()
}
func B() {
	time.Sleep(3 * time.Second)
	C()
}
func C() {
	mu.RLock()
	defer mu.RUnlock()
}

1.3map安全锁

这个字典类型提供了一些常用的键值存取操作方法,并保证了这些操作的并发安全
var ma sync.Map //该类型是开箱即用,只需要声明既可
ma.Store("key", "value") // 存储值
ma.Delete("key") //删除值
ma.LoadOrStore("key", "value")// 获取值,如果没有则存储
fmt.Println(ma.Load("key"))//获取值

//遍历
ma.Range(func(key, value interface{}) bool {
  fmt.Printf("key:%s ,value:%s \n", key, value)
  //如果返回:false,则退出循环,
  return true
})

2.互斥锁,读写锁,死锁问题是怎么解决

互斥锁
互斥锁就是互斥变量mutex,用来锁住临界区的.

条件锁就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就是锁住了。当资源被分配到了,条件锁打开,进程继续运行;读写锁,也类似,用于缓冲区等临界资源能互斥访问的。

读写锁
通常有些公共数据修改的机会很少,但其读的机会很多。并且在读的过程中会伴随着查找,给这种代码加锁会降低我们的程序效率。读写锁可以解决这个问题。

死锁
一般情况下,如果同一个线程先后两次调用lock,在第二次调用时,由于锁已经被占用,该线程会挂起等待别的线程释放锁,然而锁正是被自己占用着的,该线程又被挂起而没有机会释放锁,因此就永远处于挂起等待状态了,这叫做死锁(Deadlock)。 另外一种情况是:若线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。

3.Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量?

Golang中Goroutine 可以通过 Channel 进行安全读写共享变量。

4.go的锁如何实现,用了什么cpu指令

原理:博客地址待填写

Mutex对外提供两个方法

Lock():加锁方法
Unlock():解锁方法

cpu指令:PAUSE暂停停顿

5.读写锁或者互斥锁读的时候能写吗?

不能。	可以同时读,但是读-写,写-写都是互斥的。
  Go中读写锁包括读锁和写锁,多个读线程可以同时访问共享数据;写线程必须等待所有读线程都释放锁以后,才能取得锁;同样的,读线程必须等待写线程释放锁后,才能取得锁,也就是说读写锁要确保的是如下互斥关系,可以同时读,但是读-写,写-写都是互斥的。
posted @ 2022-03-03 18:09  Jeff的技术栈  阅读(106)  评论(0编辑  收藏  举报
回顶部