hi Michael,
from my understanding: if you only call refresh from somefunc and
locking the body should be fine. however i strongly advise not to export
refresh, otherwise it is a broken api. and someone, someday will call
refresh without that lock. if refresh should be part of the accessible
api, then split the function into two and use the same lock in the
exported Refresh method that locks and than calls the unexported refresh
method with the implementation.
This is a common pattern in go, because there is no re-entrant mutex in
the std lib.
hope that helps, have fun
On 9/12/21 2:00 AM, Michael Dwyer wrote:
Presently working on a Data Race and have some questions on how to proceed.
The code example is a hypothetical mock up of the actual code under
review, but is a fair representation.
The struct used by both functions is named Foo.
In the hypothetical, SomeFunc() reads variable from foo.bar, checking
for nil,
if nil SomeFunc() calls a Foo method Refresh().
Foo method Refresh() calls function DoSomeCalc() assigned to foo.bar and
returned back to method SomeFunc()
The race detector flags the read of foo.bar in method SomeFunc() in the
if statement,
and flags the write of foo.bar in method Refresh().
The problem I see is that in method SomeFunc() the if statement does a read,
but it too also does an assignment to foo.bar.
My initial thought is to add a sync.Lock() at the beginning of method
SomeFunc(),
followed by a defer sync.UnLock(),
that will be held until method SomeFunc() exists.
I state this because method SomeFunc() also does an assignment to
variable foo.bar.
So, a sync.RLock() would be insufficient to protect variable foo.bar
My only concern is the call to method Refresh(), which also writes to
foo.bar.
If my understanding is correct, this should work, because the lock is
initiated in method SomeFunc(), held to the exit of the method.
With the call to method Refresh() occurring within method SomeFunc() the
lock should protect variable foo.bar from other goroutines trying to
update this variable.
Asking this question to confirm my thought process is correct.
If there is an edge case I missed, please advise.
func (foo *Foo) SomeFunc() fields.SomeVariable {
if foo.bar == nil { <=== Race detector flags
this read
foo.bar = foo.ReFresh()
}
return foo.bar
}
func (foo *Foo) ReFresh() fields.SomeVariable {
foo.bar = DoSomeCalc(foo) <=== Race detector flags
this write
return foo.bar
}
THANX(MKD).
--
You received this message because you are subscribed to the Google
Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to golang-nuts+unsubscr...@googlegroups.com
<mailto:golang-nuts+unsubscr...@googlegroups.com>.
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/7226a9db-1215-411d-b769-56a9f97d34fdn%40googlegroups.com
<https://groups.google.com/d/msgid/golang-nuts/7226a9db-1215-411d-b769-56a9f97d34fdn%40googlegroups.com?utm_medium=email&utm_source=footer>.
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/7538983b-3fc4-8004-8a62-01ca78f53308%40mb0.org.