Running your example with some debug logging, it looks like whenever the selector thread gets woken up by a "b"
message, it hits this "spurious wakeup" case and goes back to sleep until woken by the next "a"
message: select.rs - source
I haven't figured out why the token isn't set on these wakeups.
More info: After each successful message is handled, the loop
in your select-receive threat creates a new Selector
. However, for some reason, the tokens from "b"
messages are pushed to a queue owned by a selector from an earlier iteration of the loop (which has since been destroyed).
This appears to happen because old hooks are not successfully removed in RecvSelection::deinit
. I suspect this is because it is comparing the addresses of trait object pointers using Arc::ptr_eq
, and running into this issue: https://github.com/rust-lang/rust/issues/46139
I submitted a fix for this here:
https://github.com/zesterer/flume/pull/69
Edit: For now, you can also work around this bug by setting codegen-units = 1
in your Cargo.toml. For example:
[profile.dev]
codegen-units = 1
[profile.release]
codegen-units = 1
To avoid similar issues in the future, I think that Arc::ptr_eq
should require Self: Sized
to avoid people accidentally falling into this trap. To my knowledge, there's no real case in which the current behaviour with trait objects would be desirable (correct me if I'm wrong). This would be a breaking change, but breakages would only be highlighting likely bugs.