在 Go 中使用互斥锁
Using mutexes in Go
我正在尝试了解互斥锁的工作原理。目前我的理解,就是为了承载原子操作,同步访问一些数据。
我在这里构建了一个队列数据结构的例子:https://github.com/arnauddri/algorithms/blob/master/data-structures%2Fqueue%2Fqueue.go
这里有一些代码:
package queue
import "sync"
type Queue struct {
queue []interface{}
len int
lock *sync.Mutex
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
q.queue = append(q.queue, el)
q.len++
}
然而,当我尝试创建队列并将项目推送到其中时,出现运行时错误:
q := New()
q.Push(1)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
我真的不明白这里发生了什么。
这里的Mutex应该如何使用?
非常感谢
看起来问题在于您从未实例化互斥体。当您 运行 New()
函数时,您正在创建一个空队列,其中包含一个可以引用互斥锁的变量,但您实际上从未告诉它这样做,这意味着此时 queue.lock == nil
.您可以通过在 New()
函数中添加实例化行来解决此问题。
queue.lock = new(sync.Mutex)
这是一个有效的游乐场演示:http://play.golang.org/p/Qa6buDaHIj
你得到那个错误是因为你没有分配任何互斥量,你只有一个指向互斥量的指针。
互斥量通常在结构内部声明并且没有指针。请参阅下面的工作示例:
http://play.golang.org/p/8LF3yVOkSW
import "sync"
type Queue struct {
len int
lock sync.Mutex // add it before the fields that are being protected by the mutex
queue []interface{}
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
q.queue = append(q.queue, el)
q.len++
}
func main() {
q := New()
q.Push(1)
}
指针的零值是nil,q.lock是nil指针,解引用nil指针会引起恐慌。
您可以使用 lock sync.Mutex 而不是 *lock sync.Mutex,Mutex 的零值是未锁定的互斥锁。
结构匿名嵌套也能解决你的问题:
package queue
import "sync"
type Queue struct {
queue []interface{}
len int
sync.Mutex
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.Lock()
defer q.Unlock()
q.queue = append(q.queue, el)
q.len++
}
我正在尝试了解互斥锁的工作原理。目前我的理解,就是为了承载原子操作,同步访问一些数据。
我在这里构建了一个队列数据结构的例子:https://github.com/arnauddri/algorithms/blob/master/data-structures%2Fqueue%2Fqueue.go
这里有一些代码:
package queue
import "sync"
type Queue struct {
queue []interface{}
len int
lock *sync.Mutex
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
q.queue = append(q.queue, el)
q.len++
}
然而,当我尝试创建队列并将项目推送到其中时,出现运行时错误:
q := New()
q.Push(1)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
我真的不明白这里发生了什么。
这里的Mutex应该如何使用?
非常感谢
看起来问题在于您从未实例化互斥体。当您 运行 New()
函数时,您正在创建一个空队列,其中包含一个可以引用互斥锁的变量,但您实际上从未告诉它这样做,这意味着此时 queue.lock == nil
.您可以通过在 New()
函数中添加实例化行来解决此问题。
queue.lock = new(sync.Mutex)
这是一个有效的游乐场演示:http://play.golang.org/p/Qa6buDaHIj
你得到那个错误是因为你没有分配任何互斥量,你只有一个指向互斥量的指针。 互斥量通常在结构内部声明并且没有指针。请参阅下面的工作示例:
http://play.golang.org/p/8LF3yVOkSW
import "sync"
type Queue struct {
len int
lock sync.Mutex // add it before the fields that are being protected by the mutex
queue []interface{}
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
q.queue = append(q.queue, el)
q.len++
}
func main() {
q := New()
q.Push(1)
}
指针的零值是nil,q.lock是nil指针,解引用nil指针会引起恐慌。 您可以使用 lock sync.Mutex 而不是 *lock sync.Mutex,Mutex 的零值是未锁定的互斥锁。 结构匿名嵌套也能解决你的问题:
package queue
import "sync"
type Queue struct {
queue []interface{}
len int
sync.Mutex
}
func New() *Queue {
queue := &Queue{}
queue.queue = make([]interface{}, 0)
queue.len = 0
return queue
}
func (q *Queue) Push(el interface{}) {
q.Lock()
defer q.Unlock()
q.queue = append(q.queue, el)
q.len++
}