uzumas
uzumas

Reputation: 678

Acquiring a lock over a memory address instead of variable in golang

I have an interface called Setter. Struct called SetterImpl implements this interface and has 2 setters, all of which set 2 interfaces.

type Setter interface {
    A() *AInterface
    B() *BInterface
}
type SetterImpl struct {
    a *AInterface
    b *BInterface
}

func (s *SetterImpl) A(a *AInterface) {
    a = a
}

func (s *SetterImpl) B(b *AInterface) {
    b = b
}

func returnSetter(a *AInterface, b *BInterface) Setter {
    return &SetterImpl{a:a, b:b}
}

The setter returned by the above method is in heap(say SHeap) and sent to gRPC server. Now, I want to update a and b within the SetterImpl such that the gRPC server uses the new values.

So I have 2 goroutines now; one is gRPC server main goroutine(say MAIN), another is a forked one(say FORKED) which simply is to update the setter fields.

If I use Mutex in FORKED, that is essentially adding a fence (like java). It does not lock any variables actually(except itself). I do not want MAIN to be able to read a and b stored in SHeap while FORKED updates them. The API threads(goroutines) in the server do not acquire Read Mutex before reading values in SHeap. So, is it even possible to do what I am trying to achieve? If yes, how do I achieve this?

Upvotes: 0

Views: 1041

Answers (2)

uzumas
uzumas

Reputation: 678

Variables can't be locked. So what I am trying to do is not possible. The work-around I did was to add a RWMutex into SetterImpl and doing

mux.RLock()
defer mux.RUnlock()

in getters of a and b in SetterImpl. And when I want to set a and b in FORKED, I used

mux.Lock()
defer mux.Unlock()

This way, if a write lock is acquired by FORKED, no read lock can be acquired at that time. This is possible as the RWLock field created in SHeap is used as global variable (i.e. this mutex is never changed and passed along FORKED)

Upvotes: 0

user10753492
user10753492

Reputation: 778

I don't think you can lock variables in Go. You can only lock a code section.

m.Lock()
// do stuff
m.Unlock()

You are creating a problem for yourself out of nothing by using the "interface" vs "Impl" pattern.

You can make your life simpler by just using a regular function. Then you can put the lock inside a function and be guaranteed that it will be protected.

Since you are making an interface, you can't guarantee anything about the content of the function that implements the interface.

Upvotes: 1

Related Questions