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
A Mutex is a method used as a locking mechanism to ensure that only one Goroutine is accessing the critical section of code at any point of time. This is done to prevent race conditions from happening. Sync package contains the Mutex.
We can make use of channels if we want to synchronize goroutines. By synchronizing, we want to make the goroutines work in a defined manner, for example, not starting the next goroutine until the previous one has finished its execution.
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)
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With