2021SC@SDUSC
Go语言的简单2D游戏库-Ebiten目录
概述
代码
主要函数
func AppendHookOnBeforeUpdate
func RunBeforeUpdateHooks
func OnSuspendAudio
func SuspendAudio
func ResumeAudio
golang中sync.RWMutex和sync.Mutex
Mutex:互斥锁
示例代码:
RWMutex:读写锁,RWMutex 基于 Mutex 实现
Lock() 和 Unlock():
RLock() 和 RUnlock():
概述
这部分代码解决的问题主要是通过钩子函数来封装一些音频组件,然后通过传入钩子函数来实现音频的恢复和暂停,通过引入sync包来实现对共享资源的上锁和解锁。
代码package hooks
import (
"sync"
)
var m sync.Mutex
var onBeforeUpdateHooks = []func() error{}
// AppendHookOnBeforeUpdate appends a hook function that is run before the main update function
// every frame.
func AppendHookOnBeforeUpdate(f func() error) {
m.Lock()
onBeforeUpdateHooks = append(onBeforeUpdateHooks, f)
m.Unlock()
}
func RunBeforeUpdateHooks() error {
m.Lock()
defer m.Unlock()
for _, f := range onBeforeUpdateHooks {
if err := f(); err != nil {
return err
}
}
return nil
}
var (
audioSuspended bool
onSuspendAudio func() error
onResumeAudio func() error
)
func OnSuspendAudio(f func() error) {
m.Lock()
onSuspendAudio = f
m.Unlock()
}
func OnResumeAudio(f func() error) {
m.Lock()
onResumeAudio = f
m.Unlock()
}
func SuspendAudio() error {
m.Lock()
defer m.Unlock()
if audioSuspended {
return nil
}
audioSuspended = true
if onSuspendAudio != nil {
return onSuspendAudio()
}
return nil
}
func ResumeAudio() error {
m.Lock()
defer m.Unlock()
if !audioSuspended {
return nil
}
audioSuspended = false
if onResumeAudio != nil {
return onResumeAudio()
}
return nil
}
主要函数
func AppendHookOnBeforeUpdate
AppendHookOnBeforeUpdate添加一个钩子函数,该钩子函数在每帧主更新函数之前运行。在访问存储钩子函数的数组之前,对该资源进行上锁,等成功添加传进来的钩子函数后,再对该资源进行解锁
func RunBeforeUpdateHooks运行钩子函数 通过使用defer 使函数在执行return语句之前执行m.Unlock()实现对资源的解锁
func OnSuspendAudio将传入的封装有要暂停音频的钩子函数存到onSuspendAudio
func SuspendAudio在上锁之后,如果audioSuspended此时为true,说明已经执行过暂停音频函数了,不能再执行,返回nil。
若audioSuspended为false,则将其设为true,告诉别人我执行过暂停音频函数了,然后若onSuspendAudio不为空,则返回函数onSuspendAudio()
func ResumeAudio恢复音频,与暂停音频类似,若audioSuspended为true,说明执行过暂停音频函数,可以继续执行函数ResumeAudio,并将audioSuspended设为false,告诉别人可以再次执行暂停音频函数。
golang中sync.RWMutex和sync.Mutex Mutex:互斥锁type Mutex struct {
// 包含隐藏或非导出字段
}
Mutex是一个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。
1、在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex
2、使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.
3、适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁叶叫做全局锁
4、在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁,会导致死锁
func (m *Mutex) Lock()
//Lock方法锁住m,如果m已经加锁,则阻塞直到m解锁。
func (m *Mutex) Unlock()
//Unlock方法解锁m,如果m未加锁会导致运行时错误。
//锁和线程无关,可以由不同的线程加锁和解锁。
示例代码:
加锁和解锁:
package main
import (
"fmt"
"sync"
)
func main() {
var L *sync.Mutex //互斥锁
L = new(sync.Mutex)
L.Lock() //加锁
defer L.Unlock() //解锁
fmt.Println("hello")
}
//结果:hello
在解锁之前加锁会导致死锁:
package main
import (
"fmt"
"sync"
)
func main() {
var L *sync.Mutex //互斥锁
L = new(sync.Mutex)
L.Lock() //加锁
//defer L.Unlock() //解锁
fmt.Println("hello")
L.Lock()//再次加锁
}
//结果:
//hello
//fatal error: all goroutines are asleep - deadlock!
RWMutex:读写锁,RWMutex 基于 Mutex 实现
type RWMutex struct {
// 包含隐藏或非导出字段
}
RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。
1、可以加多个读锁或者一个写锁
2、写锁权限高于读锁,有写锁时优先进行写锁定
3、读锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁
4、写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占
func (rw *RWMutex) Lock()
//Lock方法将rw锁定为写入状态,禁止其他线程读取或者写入。
func (rw *RWMutex) Unlock()
//Unlock方法解除rw的写入锁状态,如果m未加写入锁会导致运行时错误。
Lock() 和 Unlock():
Lock() 加写锁,Unlock() 解写锁
package main
import (
"fmt"
"sync"
)
func main() {
var L *sync.RWMutex //读写锁
L = new(sync.RWMutex)
L.Lock() //加锁
fmt.Println("hello")
L.Unlock() //解锁
}
func (rw *RWMutex) RLock()
//RLock方法将rw锁定为读取状态,禁止其他线程写入,但不禁止读取。
func (rw *RWMutex) RUnlock()
//Runlock方法解除rw的读取锁状态,如果m未加读取锁会导致运行时错误。
RLock() 和 RUnlock():
1.RLock() 加读锁,RUnlock() 解读锁。
2.RLock() 加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加载多个。
3.在没有读锁的情况下调用 RUnlock() 会导致 panic 错误。
4.当RUnlock多于RLock时,会报错,进入死锁
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)