On Tue, May 6, 2014 at 6:34 PM, Kai Skye wrote:
Well, I figure that the race condition is benign here, since even if a
goroutine sees an old value, all I care about is that by the time wg.Wait()
is finished, condition is either set or unset. But please correct me if I'm
wrong about that.
In general all races should be avoided. I agree that this one is
likely benign.
I like the idea of using channels but I couldn't figure out how to get it
playing nicely with WaitGroup. In your example, you do:
wg.Wait()
close(c)
condition, _ := <-c
But I am under the impression that reading from a closed channel always
returns a zero value, so condition would always be false in this case. Is
that not true here?
A close of a channel is in effect sent on the channel. The close will
only be seen after all other values have been read. So in this case
if any goroutine wrote true to the channel, that is the value that
will wind up in the variable "condition". If no goroutine wrote to
the channel, then it will be closed, and "condition" will be set to
the zero value == false.
In fact I now see that the _ is pointless and it would fine to write
simply
condition := <-c
Otherwise, if we don't close the channel and just try to
do "condition := <-c", then it would hang if "c <- true" is never called by
any goroutine. Although, perhaps I could use a select statement after
wg,Wait(), as in:
wg.Wait()
select {
case <-c:
// do stuff with condition == true
default:
// do other stuff
}
Does that seem reasonable?
Yes, that will also work, it's just more verbose.
Ian
On Tuesday, May 6, 2014 9:12:28 PM UTC-4, Ian Lance Taylor wrote:On Tue, May 6, 2014 at 6:55 AM, wrote:
Here is some example code that demonstrates my question:
var condition bool
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item) {
if meetsCondition(item) {
condition = true
}
wg.Done()
}(item)
}
wg.Wait()
// is it safe to check condition here?
Does wg.Wait() act as a memory barrier so that it's safe to check
condition?
If not, what's the best way to represent this idiom?
(atomic.Load/Store?)
It is safe to check condition after wg.Wait returns.
On the other hand you have several goroutines racing to set condition,
so you should be using atomic.Store anyhow.
Or just send a value on a channel, that always works and doesn't lead
to any of these issues. Untested:
var wg sync.WaitGroup
c := make(chan bool, 1)
for _, item := range items {
wg.Add(1)
go func(item) {
if meetsCondition(item) {
select {
case c <- true:
default:
}
}
wg.Done()
}(item)
}
wg.Wait()
close(c)
condition, _ := <-c
On Tue, May 6, 2014 at 6:34 PM, Kai Skye wrote:Well, I figure that the race condition is benign here, since even if a
goroutine sees an old value, all I care about is that by the time wg.Wait()
is finished, condition is either set or unset. But please correct me if I'm
wrong about that.
I like the idea of using channels but I couldn't figure out how to get it
playing nicely with WaitGroup. In your example, you do:
wg.Wait()
close(c)
condition, _ := <-c
But I am under the impression that reading from a closed channel always
returns a zero value, so condition would always be false in this case. Is
that not true here? Otherwise, if we don't close the channel and just try to
do "condition := <-c", then it would hang if "c <- true" is never called by
any goroutine. Although, perhaps I could use a select statement after
wg,Wait(), as in:
wg.Wait()
select {
case <-c:
// do stuff with condition == true
default:
// do other stuff
}
Does that seem reasonable?
On Tuesday, May 6, 2014 9:12:28 PM UTC-4, Ian Lance Taylor wrote:On Tue, May 6, 2014 at 6:55 AM, wrote:
Here is some example code that demonstrates my question:
var condition bool
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item) {
if meetsCondition(item) {
condition = true
}
wg.Done()
}(item)
}
wg.Wait()
// is it safe to check condition here?
Does wg.Wait() act as a memory barrier so that it's safe to check
condition?
If not, what's the best way to represent this idiom?
(atomic.Load/Store?)
It is safe to check condition after wg.Wait returns.
On the other hand you have several goroutines racing to set condition,
so you should be using atomic.Store anyhow.
Or just send a value on a channel, that always works and doesn't lead
to any of these issues. Untested:
var wg sync.WaitGroup
c := make(chan bool, 1)
for _, item := range items {
wg.Add(1)
go func(item) {
if meetsCondition(item) {
select {
case c <- true:
default:
}
}
wg.Done()
}(item)
}
wg.Wait()
close(c)
condition, _ := <-c
Ian
--
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+unsubscribe@googlegroups.com.
For more options, visit
https://groups.google.com/d/optout.--
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+unsubscribe@googlegroups.com.
For more options, visit
https://groups.google.com/d/optout.