A question about A sync.Once implementation.

145 views
Skip to first unread message

wu.pur...@gmail.com

unread,
May 7, 2019, 8:55:06 AM5/7/19
to golang-nuts
Hi, 
        I did a quiz recently, but I'm having problem with the answer.
        
package doublecheck

import (
       
"sync"
)

type Once struct {
        m    sync
.Mutex
       
done uint32
}

func (o *Once) Do(f func()) {
       
if o.done == 1 {
               
return
       
}

        o
.m.Lock()
       
defer o.m.Unlock()
       
if o.done == 0 {
                o
.done = 1
               
f()
       
}
}

Question

  •  A: can't compile
  •  B: can run that implemented the singleton pattern correctly
  •  C: can run but has not implemented the singleton pattern, function f may run multi times.
  •  D: programms will be panic when use this Once concurrently.
Some other people and I think the answer is B, but the author says the answer is C.

We think this implements happen-before, but the author doesn't think so.

Can anyone help to explain this?

Thanks!

Robert Johnstone

unread,
May 7, 2019, 9:33:41 AM5/7/19
to golang-nuts
Hello,

The code contains two bugs.

1) The load and store of o.done needs to be done using atomic stores.  
2) The statement to set o.done = 1 needs to be after the call to f.  Otherwise, another goroutine can hit the check at the top of Done and return before the code in f has completed.

Ian Lance Taylor

unread,
May 7, 2019, 10:08:39 AM5/7/19
to wu.pur...@gmail.com, golang-nuts
On Tue, May 7, 2019 at 5:55 AM <wu.pur...@gmail.com> wrote:
>
> Hi,
> I did a quiz recently, but I'm having problem with the answer.
> Quiz: https://github.com/smallnest/go-concurrent-quiz#-quiz-4

When sending code, please just send plain text or a link to
play.golang.org. Thanks. I can't actually read the
colorized-on-black text you posted.

Ian

wudi....@bytedance.com

unread,
May 8, 2019, 12:41:59 AM5/8/19
to golang-nuts
I'm quite sorry for that. This is my first time posting code here.
Here's go playground link: https://play.golang.org/p/9xVjoD7rI0F.

在 2019年5月7日星期二 UTC+8下午10:08:39,Ian Lance Taylor写道:

wudi....@bytedance.com

unread,
May 8, 2019, 12:41:59 AM5/8/19
to golang-nuts
Hi,
    Thanks for your reply.
    The second bug is a known issue, so let’s ignore that. In that case, I think function f still can only be executed once.
    But why does the load and store of o.done need to be done using atomic operations? I suppose there’s mutex assuring the happens-before.


在 2019年5月7日星期二 UTC+8下午9:33:41,Robert Johnstone写道:

White Pure

unread,
May 8, 2019, 12:42:43 AM5/8/19
to golang-nuts
Hi,
    Thanks for your reply.
    The second bug is a known issue, so let’s ignore that. In that case, I think function f still can only be executed once.
    But why does the load and store of o.done need to be done using atomic operations? I suppose there’s mutex assuring the happens-before.


在 2019年5月7日星期二 UTC+8下午9:33:41,Robert Johnstone写道:
Hello,

Kurtis Rader

unread,
May 8, 2019, 12:49:45 AM5/8/19
to White Pure, golang-nuts
On Tue, May 7, 2019 at 9:42 PM White Pure <wu.pur...@gmail.com> wrote:
Hi,
    Thanks for your reply.
    The second bug is a known issue, so let’s ignore that. In that case, I think function f still can only be executed once.
    But why does the load and store of o.done need to be done using atomic operations? I suppose there’s mutex assuring the happens-before.

You seem to be using two different email accounts to comment on this thread. That is confusing, at best, and sock puppeting, at worst. Don't do that.

Also, your text in the message I am replying to is in a very light grey color. Which makes it hard to read on a white background. Please don't use styled text that modifies the colors on a general purpose mailing list. Not everyone is using color preferences compatible with your preferences.
 
--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

roger peppe

unread,
May 8, 2019, 7:15:26 AM5/8/19
to Kurtis Rader, White Pure, golang-nuts
It seems clear to me that C ("can run but has not implemented the singleton pattern, function f may run multi times") is not the correct answer, because I'm pretty sure that f cannot run more than once.

However, it's still not a correct Once implementation, because as has already been pointed out, the Do method can return before the function has completed.

The reason why f cannot run more than once is that if you don't have the initial non-atomic test of o.done, then the function cannot run more than once, and the extra condition only reduces the number of times that f can be called.

The implementation would be incorrect even if the `o.done = 1` assignment was moved before the call to f, because there's no happens-before relationship between the `o.done == 1` check and either of the statements within the mutex. This means that it's possible for the `o.done == 1` check to report true but for the caller to see memory that indicates that f hasn't been called.

If you run this code with the race detector enabled, it will report an error. That should be good enough reason not to use code like this.

Here's a complete example: https://play.golang.org/p/vWVXzRBPMNe
The question is: according to the Go memory model, what's the set of possible things that that program can print?

I think it could print "unexpected value 0" but not "unexpected value 2".


--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CABx2%3DD8hZAt0DRyrTEnunU2%3D6_y2hheDB48RZft7BAS4a7fEcg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

White Pure

unread,
May 8, 2019, 11:52:13 PM5/8/19
to golang-nuts
Hi, 
    You are right, I did some modification to your code and make it able to reproduce everytime: https://play.golang.org/p/y6vxC_DNjp9
    Thanks!

在 2019年5月8日星期三 UTC+8下午7:15:26,rog写道:
It seems clear to me that C ("can run but has not implemented the singleton pattern, function f may run multi times") is not the correct answer, because I'm pretty sure that f cannot run more than once.

However, it's still not a correct Once implementation, because as has already been pointed out, the Do method can return before the function has completed.

The reason why f cannot run more than once is that if you don't have the initial non-atomic test of o.done, then the function cannot run more than once, and the extra condition only reduces the number of times that f can be called.

The implementation would be incorrect even if the `o.done = 1` assignment was moved before the call to f, because there's no happens-before relationship between the `o.done == 1` check and either of the statements within the mutex. This means that it's possible for the `o.done == 1` check to report true but for the caller to see memory that indicates that f hasn't been called.

If you run this code with the race detector enabled, it will report an error. That should be good enough reason not to use code like this.

Here's a complete example: https://play.golang.org/p/vWVXzRBPMNe
The question is: according to the Go memory model, what's the set of possible things that that program can print?

I think it could print "unexpected value 0" but not "unexpected value 2".


On Wed, 8 May 2019 at 05:49, Kurtis Rader <kra...@skepticism.us> wrote:
On Tue, May 7, 2019 at 9:42 PM White Pure <wu.pu...@gmail.com> wrote:
Hi,
    Thanks for your reply.
    The second bug is a known issue, so let’s ignore that. In that case, I think function f still can only be executed once.
    But why does the load and store of o.done need to be done using atomic operations? I suppose there’s mutex assuring the happens-before.

You seem to be using two different email accounts to comment on this thread. That is confusing, at best, and sock puppeting, at worst. Don't do that.

Also, your text in the message I am replying to is in a very light grey color. Which makes it hard to read on a white background. Please don't use styled text that modifies the colors on a general purpose mailing list. Not everyone is using color preferences compatible with your preferences.
 
--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

--
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 golan...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages