【Golang 面试 - 进阶题】每日 3 题(四)
创始人
2024-12-04 09:33:01
0

✍个人博客:Pandaconda-CSDN博客

📣专栏地址:http://t.csdnimg.cn/UWz06

📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪

10. G o 可重入锁如何实现?

概念:

可重入锁又称为递归锁,是指在同一个线程在外层方法获取锁的时候,在进入该线程的内层方法时会自动获取锁,不会因为之前已经获取过还没释放再次加锁导致死锁。

为什么 Go 语言中没有可重入锁?

Mutex 不是可重入的锁。Mutex 的实现中没有记录哪个 goroutine 拥有这把锁。理论上,任何 goroutine 都可以随意地 Unlock 这把锁,所以没办法计算重入条件,并且Mutex 重复 Lock 会导致死锁。

如何实现可重入锁?

实现一个可重入锁需要这两点:

  • 记住持有锁的线程

  • 统计重入的次数

package main import (     "bytes"     "fmt"     "runtime"     "strconv"     "sync"     "sync/atomic" ) type ReentrantLock struct {     sync.Mutex     recursion int32 // 这个goroutine 重入的次数     owner     int64 // 当前持有锁的goroutine id } // Get returns the id of the current goroutine. func GetGoroutineID() int64 {     var buf [64]byte     var s = buf[:runtime.Stack(buf[:], false)]     s = s[len("goroutine "):]     s = s[:bytes.IndexByte(s, )]     gid, _ := strconv.ParseInt(string(s), 10, 64)     return gid } func NewReentrantLock() sync.Locker {     res := &ReentrantLock{         Mutex:     sync.Mutex{},         recursion: 0,         owner:     0,     }     return res } // ReentrantMutex 包装一个Mutex,实现可重入 type ReentrantMutex struct {     sync.Mutex     owner     int64 // 当前持有锁的goroutine id     recursion int32 // 这个goroutine 重入的次数 } func (m *ReentrantMutex) Lock() {     gid := GetGoroutineID()     // 如果当前持有锁的goroutine就是这次调用的goroutine,说明是重入     if atomic.LoadInt64(&m.owner) == gid {         m.recursion++         return     }     m.Mutex.Lock()     // 获得锁的goroutine第一次调用,记录下它的goroutine id,调用次数加1     atomic.StoreInt64(&m.owner, gid)     m.recursion = 1 } func (m *ReentrantMutex) Unlock() {     gid := GetGoroutineID()     // 非持有锁的goroutine尝试释放锁,错误的使用     if atomic.LoadInt64(&m.owner) != gid {         panic(fmt.Sprintf("wrong the owner(%d): %d!", m.owner, gid))     }     // 调用次数减1     m.recursion--     if m.recursion != 0 { // 如果这个goroutine还没有完全释放,则直接返回         return     }     // 此goroutine最后一次调用,需要释放锁     atomic.StoreInt64(&m.owner, -1)     m.Mutex.Unlock() } func main() {     var mutex = &ReentrantMutex{}     mutex.Lock()     mutex.Lock()     fmt.Println(111)     mutex.Unlock()     mutex.Unlock() }

 11. Cond 是什么?

在 Go 语言中,sync.Cond 是一个条件变量的实现,它可以在多个 Goroutine 之间传递信号和数据。条件变量是一种同步机制,用于解决某些 Goroutine 需要等待某个事件或条件发生的问题。

sync.Cond 是基于 sync.Mutexsync.RWMutex 的,它提供了 Wait()Signal()Broadcast() 三个方法。

  • Wait():释放锁并阻塞当前 Goroutine,直到调用 Signal()Broadcast() 并重新获得锁。在阻塞期间,Goroutine 处于等待状态并且不会消耗 CPU 资源。

  • Signal():唤醒一个等待中的 Goroutine。

  • Broadcast():唤醒所有等待中的 Goroutine。

下面是一个简单的示例,展示了如何使用 sync.Cond 实现多个 Goroutine 之间的通信:

package main import (     "fmt"     "sync"     "time" ) func main() {     var mutex sync.Mutex     cond := sync.NewCond(&mutex)     ready := false     for i := 0; i < 5; i++ {         go func(i int) {             mutex.Lock()             defer mutex.Unlock()             for !ready {                 cond.Wait()             }             fmt.Printf("Goroutine %d is now running\n", i)         }(i)     }     time.Sleep(time.Second * 1)     mutex.Lock()     ready = true     cond.Broadcast()     mutex.Unlock()     time.Sleep(time.Second * 1) }

在这个例子中,我们创建了一个 sync.Cond 实例,将它和一个 sync.Mutex 关联起来。然后我们启动了 5 个 Goroutine,在其中每个 Goroutine 上等待一个条件变量。我们在主 Goroutine 中等待一秒钟,然后发送一个 Broadcast 信号,通知所有等待中的 Goroutine 可以开始执行了。在接收到 Broadcast 信号后,所有 Goroutine 将开始执行,并输出一些消息。

12. B r oadcast 和 Signal 区别

在 Go 语言中,sync.Cond 类型提供了 Broadcast()Signal() 两个方法来唤醒等待条件变量的 Goroutine。这两个方法的区别在于:

  • Signal() 方法只会唤醒等待条件变量的一个 Goroutine,具体哪个 Goroutine 会被唤醒是不确定的。如果多个 Goroutine 等待同一个条件变量,那么只会有一个 Goroutine 被唤醒,其他 Goroutine 仍然会继续等待条件变量。

  • Broadcast() 方法会唤醒所有等待条件变量的 Goroutine,使它们都开始运行。如果多个 Goroutine 等待同一个条件变量,那么所有 Goroutine 都会被唤醒。

一般来说,使用 Signal() 方法可以提高程序的效率,因为只需要唤醒一个 Goroutine,其他 Goroutine 仍然会等待条件变量,不会消耗 CPU 资源。但是,如果有多个 Goroutine 都需要同时等待条件变量,那么使用 Broadcast() 方法才能保证它们都能被唤醒,否则可能会出现死锁等问题。

总之,Broadcast() 方法是一种安全可靠的方法,但是可能会导致一些性能问题。而 Signal() 方法则可以提高程序的效率,但是需要确保程序的正确性。在实际应用中,应该根据具体情况选择合适的方法。

相关内容

热门资讯

2分钟德州透视挂!hhpoke... 2分钟德州透视挂!hhpoker开挂教程,德州透视插件,详细教程(有挂功能)1、完成德州透视插件透视...
九分钟开辅助!wepoker辅... 九分钟开辅助!wepoker辅助软件价格(透视底牌)详细辅助程序(本来是真的有挂)1、任何wepok...
9分钟透视插件!hh poke... 9分钟透视插件!hh poker软件,hhpoker是正品吗,详细教程(有挂智能)1、hh poke...
7分钟插件辅助!wepoker... 7分钟插件辅助!wepoker买钻石有用吗(透视底牌)详细辅助插件(果然是有挂)7分钟插件辅助!we...
八分钟作弊实战!hhpoker... 八分钟作弊实战!hhpoker脚本,hhpoker辅助靠谱吗,详细教程(有挂安装)1、完成hhpok...
二分钟苹果版!wepoker有... 二分钟苹果版!wepoker有辅助器吗(透视底牌)详细辅助免费(切实真的是有挂)1、点击下载安装,插...
八分钟破解工具!德州透视hhp... 八分钟破解工具!德州透视hhpoker,hh poker辅助器先试用,详细教程(有挂插件)1、该软件...
二分钟作弊!wepoker私人... 二分钟作弊!wepoker私人局可以透视(透视底牌)详细辅助作弊器(本来真的有挂);暗藏猫腻,小编详...
五分钟外挂!德扑HHpoker... 五分钟外挂!德扑HHpoker有挂吗(透视脚本)详细辅助助手(确实真的是有挂)1、任何ai辅助神器的...
5分钟新号!wepoker透视... 5分钟新号!wepoker透视器免费(透视底牌)详细辅助外挂(确实是真的有挂)1、打开软件启动之后找...