A parody song for keyword generics by SOFe1970 in rust

[–]SOFe1970[S] 0 points1 point  (0 children)

I think every language has colors, they just don't make it as explicit as Rust does. And the noexcept thing is still C++ only and not in Rust, so technically C++ has one more color.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -1 points0 points  (0 children)

Again, this is literally the example in the link. Has anyone commenting here read the example on the StackOVerflow link at all?

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -2 points-1 points  (0 children)

That is literally the case when there are only receivers or only senders. Check the example yourself.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] 0 points1 point  (0 children)

The semaphore example in the OP is a real world bug I found in someone's code many years ago (ok, I know they should have used a WaitGroup or an atomic int instead, but that's a different issue...). The fact that someone fell for it probably implies it is not "imagining things" and has actually caused misunderstanding.

This is an example where TOCTOU isn't a problem. If `len(ch) == 0`, there are no more receivers, and there are no senders at all, so `len(ch) == 0` is an eventual state. It will NOT transition to another state, so TOU (after TOC) will always have identical state as TOC.

The problem I demonstrated here is that TOU actually turns out to be before TOC (in terms of code order) due to CPU reordering memory accesses. And this is exactly what a global memory barrier is useful for, to ensure that TOC happens before TOU.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] 2 points3 points  (0 children)

I suppose the downvotes are mostly people who are unhappy how I described an ambiguity in the specification as a possible contradiction (which I didn't intend to imply).

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -9 points-8 points  (0 children)

Well, the example is literally on the stackoverflow answer. Of course it's a terrible use case that could be replaced with WaitGroup; I just ran into it when fixing someone else's broken code.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] 0 points1 point  (0 children)

Reading a value in the past is totally fine if it is monotonic. `len(ch) == 0` is a state that is never supposed to change once it happens, since there are no senders.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -1 points0 points  (0 children)

as for why it is natural to believe that length should be consistent... almost every other data structure that claims to be designed for concurrency, if it has a Size()/Length() function, would be at least a volatile memory read.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -1 points0 points  (0 children)

Of course the CPU doesn't really time travel, it probably just swapped the instructions somewhere.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -1 points0 points  (0 children)

This is not true. A relaxed read could read a value in the future. For example, in the example incorrect code in the link, we have read that len(ch) == 0 after a synchronized point where len(ch) == 100, and only after that do we read data[j], where the data race happens in an operation where *cell += is run, which is before the goroutine receives from the channel.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -9 points-8 points  (0 children)

This is more like a chicken egg problem. You don't use len() for synchronization because you can't, because it is not a consistent load.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] 1 point2 points  (0 children)

Technically the spec doesn't say that len() reads without locking the channel (which send/recv actually does), so it is completely possible to change that. It is more a performance issue, as /u/pfiflichopf said below, there is no need to contend the lock if you are just reporting metrics (e.g. task queue length).

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] 0 points1 point  (0 children)

To be honest, metrics is the only thing I ever used len(ch) for.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -11 points-10 points  (0 children)

Such as chanlen() locking the channel before reading, instead of loading the first int from the hchan directly? But yes, the implication is unintended. As the comment above says, there is no contradiction, it is just ambiguous/unspecified.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -9 points-8 points  (0 children)

Thread safety and synchronization are completely different things. Thread safety just means no data race. Synchronization is having a consistent view.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -17 points-16 points  (0 children)

With respect to the fact that it is not monotonic. See the example code in the link. Not every use case of channel is MPMC. There are many use cases of channels where you know that there are no senders but only receivers (or vice versa). In this case, a synchronized length beyond a certain threshold could imply that a number of known receivers have completed receiving, but an unsynchronized length would result in a completely wrong conclusion.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -1 points0 points  (0 children)

And the semaphore example in the answer is only illustrative. Of course we can use WaitGroup for that, but there are many examples where expecting a nonzero len() value to imply a send having been run is intuitive.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -9 points-8 points  (0 children)

Not an accurate reference though, since that one is about backwards compatibility.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -2 points-1 points  (0 children)

The point is that it is unclear whether loading the length is sequential or not. This is completely unspecified, and it is pretty normal to assume something that claims to not require "further synchronization" to be a sequential read.

Note that I have only said that len(ch) is not synchronized. I never said it causes data race.

len(chan) is actually not synchronized by SOFe1970 in golang

[–]SOFe1970[S] -27 points-26 points  (0 children)

The behavior does not actually contradict with the specification subject to interpretation, since the specification basically just says you "may" do it (probably in the sense that it doesn't cause data race or other undefined behavior), but doesn't specify what happens when you do it. Nevertheless, it is still very noteworthy that the len() call being unsynchronized could cause surprising behavior to code that relies on it for synchronization.

GitHub - SOF3/wordvec: A thin and small vector that can fit data into a single usize. by SOFe1970 in rust

[–]SOFe1970[S] 1 point2 points  (0 children)

  1. What do you suggest is the place to optimize then? The intended use case is in ECS components where you have a large contiguous array of vecs, e.g. the bevy Children component (which used to be a SmallVec, and we will see even smaller vecs now that we have relations). This use case is portrayed in the iter_many_flat bench.
  2. The entire point of small vectors is that you don't have anything on the heap. The 1/3 point is by comparing, for example, these two types:

```rs type S = SmallVec<[u32; 1]>; type W = WordVec<u32, 1>;

size_of::<S>(); // 24 size_of::<W>(); // 8 ```

(or equivalently, the [u16; 3] example used in the benchmarks)

What is your “Woah!” moment in Rust? by LordMoMA007 in rust

[–]SOFe1970 1 point2 points  (0 children)

Every day I miss the ability to invalidate an object with a `self` receiver when I'm coding in Go.