Actually, in thinking about this some more, the atomics are completely 
unnecessary. Your solution being the best, but even without it, the channels 
create a happens before scenario - between the write of closed and “the channel 
close” and the read of closed. That is, for a channel to be reported as closed 
all other writes prior must be visible. 

> On Sep 2, 2019, at 6:52 PM, Robert Engels <reng...@ix.netcom.com> wrote:
> 
> As far as I know you are attributing properties to the memory model that 
> don’t yet exist - they’re working on it. Even the “happens before” in 
> relation to atomics is not yet defined. The position from the Go “team” so 
> far has been, whatever the behavior you see, that’s the spec (in terms of 
> memory model)
> 
> Still, I would hope the memory model would cover this case as it would 
> (probably) avoid unnecessary atomic writes. In this case if there were atomic 
> Boolean or bytes it wouldn’t be subject to tearing, maybe int32 in most 
> platforms. 
> 
> Still, like I said, if you want add the atomic writes, go ahead. This is 
> definitely safer. But I think when the full memory model spec arrives it 
> won’t be necessary. 
> 
>> On Sep 2, 2019, at 6:02 PM, roger peppe <rogpe...@gmail.com> wrote:
>> 
>> 
>> 
>>> On Mon, 2 Sep 2019, 21:32 robert engels, <reng...@ix.netcom.com> wrote:
>>> (you’re comments were quoted, but I think I am replying correctly).
>>> 
>>> The memory barriers provided by the Write Lock, and release will force the 
>>> flush to memory of all mutations before the flush (the closed mutation) - 
>>> meaning the atomic read will read the correct value.
>> 
>> 
>> In this case, I'm much more interested in writing Go code that's correct 
>> according to the spec than Go code that happens to work on some current 
>> architecture. Let's try to make code that's "obviously correct" rather than 
>> "not obviously incorrect". The memory model has no mention of "memory 
>> barriers" or "flushing".
>> 
>>> 
>>> There is a chance that a fully specified memory model could make that not 
>>> be possible, but in the current de-facto memory model it is going to be the 
>>> case on any CPU architecture I’m aware of. Some transactional memory 
>>> systems might be able to avoid the flush on the ‘closed’, but unlikely.
>>> 
>>> I would welcome you writing a test case to demonstrate this not being the 
>>> case and failing.
>> 
>> 
>> On a 32 bit architecture, the 64 bit write could easily be split across two 
>> non-atomic operations. AFAIK there's nothing about the atomic read that says 
>> that it couldn't observe a partial write by one of the write operations 
>> inside the mutex. It may well be possible to write a test case to 
>> demonstrate the issue on a 32-bit ARM machine. And even if it isn't, I would 
>> much always flag up code like this in a code review as being too subtle and 
>> prone to potential errors.
>> 
>>> 
>>> The reason the race detector reports a race is because it expects all 
>>> access to be guarded by the same guard, the Lock/Release must perform the 
>>> same memory barriers on the SMP systems I’m aware of.
>> 
>> 
>> Yes. That's what the memory model expects, and how Go code should be 
>> written. If code fails when run with the race detector, it should be fixed, 
>> IMHO.
>> 
>>> 
>>> The comment on the better “read” method is definitely the way to go. It 
>>> still encapsulates the channel(s), and avoids any of the ambiguity of the 
>>> memory model (while probably improving the performance a bit).
>>> 
>>> Agreed that the encapsulation can cause issues like you describe, but the 
>>> response was originally related to “priority channels”, and I was 
>>> demonstrating a technique (with additional channels behind the struct) that 
>>> would allow easy implementations of priorities. But the code I provided 
>>> certainly simplifies the case of multi writer/readers with indeterministic 
>>> behavior/shutdown (without using panic/recover which is probably the 
>>> easiest for the simple case).
>>> 
>>> 
>>>> On Sep 2, 2019, at 11:16 AM, roger peppe <rogpe...@gmail.com> wrote:
>>>> 
>>>>>> Btw, the removing of the GOMAXPROCS causes things to execute serially- 
>>>>>> which is fine according to the spec - but it does make demonstrating 
>>>>>> certain concurrency structs/problems pretty difficult.
>>>>>> Unless something's changed recently, all programs in the playground 
>>>>>> execute without parallelism, so setting GOMAXPROCS shouldn't have any 
>>>>>> effect. The fact that it does have an affect appears to be a bug. I'd 
>>>>>> suggest reporting it as an issue.
>>>>>> 
>>>>>> As I pointed out in another reply, I am fairly certain the atomic 
>>>>>> operations must be valid in these cases due to the happens before 
>>>>>> relationship of them and mutexes.
>>>>>> In that other reply:
>>>>>> 
>>>>>> You can simply validate it by run: go run -race main.go for you program: 
>>>>>> https://play.golang.org/p/JRSEPU3Uf17
>>>>>> Not true. The race detector does not detect certain cases and can 
>>>>>> overreport.
>>>>>> Firstly, AFAIK there is no implied happens-before relationship between a 
>>>>>> non-atomic write to a variable and an atomic read from a variable, 
>>>>>> because there is no synchronization event associated with the atomic 
>>>>>> read.
>>>>>> 
>>>>>> Secondly, I am aware that the race detector can give false negatives in 
>>>>>> some cases, but it should not provide false positives AFAIK. There's 
>>>>>> only one such case that I'm aware of, and that's quite a different issue.
>>>>>> 
>>>>>> Given that the race detector reports a race in this very clear and 
>>>>>> simple case, ISTM that your program is wrong.
>>>>>> 
>>>>>> From https://golang.org/ref/mem:
>>>>>> 
>>>>>> If you must read the rest of this document to understand the behavior of 
>>>>>> your program, you are being too clever.
>>>>>> 
>>>>>> Don't be clever.
>>>>>> Also, there's really no point in the atomic read. You could implement 
>>>>>> the Read method as follows:
>>>>>> 
>>>>>> func (c *MultiWriterIntChan) Read() (int, bool) {
>>>>>>  x, ok := <-c.ch
>>>>>>  return x, ok  
>>>>>> }
>>>>>> That is, let the close state flow naturally downstream via the channel. 
>>>>>> That way it will still work correctly if you start to use a buffered 
>>>>>> channel, for example.
>>>>>> 
>>>>>> I don’t agree that returning the channel is a proper design, it breaks 
>>>>>> the encapsulation. Technically mine could use multiple channels behind 
>>>>>> the scenes - yours cannot.
>>>>>> There's a trade-off here. By encapsulating in a method, you make it 
>>>>>> harder to wait for values in combination with other events (you'd need 
>>>>>> to create a goroutine to call your Read method and send the result to a 
>>>>>> channel, adding buffering, context switch overhead, and more state that 
>>>>>> needs to be explicitly shut down). 
>>>> 
>>>> 
>>>> -- 
>>>> 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/CAJhgaci57DOYHOk7C%3DjM8B6wenCxYv4JvNn2%3D13OGcd66Yc3EA%40mail.gmail.com.
>>> 
> -- 
> 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/1753A5A2-5642-49A7-8815-5CC727E67F16%40ix.netcom.com.

-- 
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/521AE3D2-2A11-4843-A880-A74C0F33BCE6%40ix.netcom.com.

Reply via email to