英文:
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
我真的不明白这里发生了什么。
我应该如何在这里使用互斥锁?
非常感谢。
英文:
I am trying to understand how mutexes work. From my understanding so far, it is made to carry atomic operations and synchronize access to some data.
I built an example of a queue data structure here: https://github.com/arnauddri/algorithms/blob/master/data-structures%2Fqueue%2Fqueue.go
Here is a bit of the code:
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++
}
However when I try to create a queue and push an item to it I get a runtime error:
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
I really don't understand what is happening here.
How should I use the Mutex here?
Many thanks
答案1
得分: 19
你之所以出现这个错误,是因为你没有分配任何互斥锁,你只有一个指向互斥锁的指针。
互斥锁通常在结构体内部声明,而且不需要使用指针。请参考下面的工作示例:
import "sync"
type Queue struct {
len int
lock sync.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)
}
希望对你有帮助!
英文:
You get that error because you did not allocated any mutex, you have only a pointer to a mutex.
Mutex usually are declared inside the structure and without the pointer. See working example below:
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)
}
答案2
得分: 7
看起来问题是你从未实例化互斥锁。当你运行New()
函数时,你创建了一个空的队列,并且有一个可以引用互斥锁的变量,但你从未告诉它实际上要这样做,这意味着此时queue.lock == nil
。你可以通过在New()
函数中添加一个实例化语句来解决这个问题。
queue.lock = new(sync.Mutex)
这里有一个可以工作的示例:http://play.golang.org/p/Qa6buDaHIj
英文:
Looks like the issue is that you're never instantiating the mutex. When you run the New()
function you're creating an empty Queue with a variable that can reference a mutex, but you never actually tell it to do so, which means that at this point queue.lock == nil
. You can fix this by adding in an instantiation line to your New()
function.
queue.lock = new(sync.Mutex)
Here is a playground demo that works: http://play.golang.org/p/Qa6buDaHIj
答案3
得分: 2
指针的零值是nil,q.lock是一个nil指针,解引用nil指针会导致恐慌。
你可以使用sync.Mutex而不是*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++
}
英文:
Zero value for a pointer is nil, q.lock is a nil pointer, dereference nil pointer will cause panic.
You can use lock sync.Mutex instead of *lock sync.Mutex, zero value for a Mutex is an unlocked mutex.
Struct anonymous nesting can also solve your problem:
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++
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论