Introduce disconnection state for channels#1114
Introduce disconnection state for channels#1114ryoqun wants to merge 1 commit intocrossbeam-rs:masterfrom
Conversation
| pub fn disconnect(&self) -> bool { | ||
| match &self.flavor { | ||
| SenderFlavor::List(chan) => chan.disconnect(), | ||
| _ => todo!(), |
There was a problem hiding this comment.
obviously, i need to add support other flavors. this is true for other 3 todo!()s.
I'll do this once i get some confirmation of the intent of merging this pr without much change.
| .fetch_or(TAIL_DISCONNECT_EXPLICIT, Ordering::SeqCst); | ||
|
|
||
| if tail & MARK_BIT == 0 { | ||
| if tail & TAIL_DISCONNECT_ANY == 0 { |
There was a problem hiding this comment.
the use of TAIL_DISCONNECT_ANY, instead of TAIL_DISCONNECT_EXPLICIT is intentional and needs a comment...
| const SHIFT: usize = 1; | ||
| // Has two different purposes: | ||
| // * If set in head, indicates that the block is not the last one. | ||
| // * If set in tail, indicates that the channel is disconnected. | ||
| const MARK_BIT: usize = 1; |
There was a problem hiding this comment.
btw, let me know if this flag dedup should be done as a preparatory pr.
| /// `false` as well, if this method is called on channels other than bounded-capacity, | ||
| /// unbounded-capacity or zero-capacity channels. |
There was a problem hiding this comment.
not coded yet. but i hope this isn't controversial behavior... ;)
| /// connected. Otherwise, this method does nothing and returns `false`. Also, this method does | ||
| /// nothing and returns `false` as well, if this method is called on channels other than | ||
| /// bounded-capacity, unbounded-capacity or zero-capacity channels. | ||
|
|
There was a problem hiding this comment.
oops, remove this empty line later....
| } | ||
|
|
||
| /// Returns `true` if the channel is disconnected. | ||
| pub(crate) fn is_disconnected(&self) -> bool { |
There was a problem hiding this comment.
I guess it's a prime time to expose this to public api? (i know there were controversial in the past..)
| /// | ||
| /// Disconnected channels can be restored connected by calling [`connect`], as long as there | ||
| /// are at least a sender and a receiver for the channel. | ||
| /// |
There was a problem hiding this comment.
i guess i need to add some motivating example here for the justification of disconnect()...
| /// Connected channels can be disconnected again by calling [`disconnect`]. | ||
| /// | ||
| /// [`disconnect`]: Self::disconnect | ||
| pub fn connect(&self) -> bool { |
There was a problem hiding this comment.
note to self: rename to reconnect()?
| .unwrap(); | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
maybe better off writing a test for possible race condition, where a sending thread disconnect/reconnect/send(T) successively , and the receiver thread may/may not see disconnected, or actual message.
| // connect should fail after all receivers has gone | ||
| assert!(!s.connect()); |
There was a problem hiding this comment.
also disconnect should fail after all receivers has gone even if the channel isn't disconnected yet.
| /// | ||
| /// Disconnected channels can be restored connected by calling [`connect`], as long as there | ||
| /// are at least a sender and a receiver for the channel. | ||
| /// |
There was a problem hiding this comment.
maybe mention about race condition among other disconnect()s and drop of the last instance of sender/receiver...
| // * If set in head, indicates that the block is not the last one. | ||
| // * If set in tail, indicates that the channel is disconnected. | ||
| const MARK_BIT: usize = 1; | ||
| const SHIFT: usize = 2; |
There was a problem hiding this comment.
(note to self): HEAD_SHIFT = 1 and TAIL_SHIFT = 2?
|
@taiki-e friendly ping. although i self-commented some after opening this pr, needing further work, I still think this pr is in some good standing for initial round of code-review. please let me know if i can do anything to moving forward this pr. |
|
@taiki-e hey, another ping from me. just want to let you know I'm very eager to work on this pr. |
(hopefully) much improved pr than #959 ....
Currently,
crossbeam-channelcompletely overlaps the channel connected status with rust sender/receiver instance aliveness. While this is uncontroversial and covers most use cases, it prevents advanced channel management.Namely:
Receiver::new_senderto channels #750While these seem to be unrelated to each other, the underlying problem is the lack of explicit channel disconnection state as described above.
Thereby, this adds the following new methods:
Fortunately, the implementation is quite simple by decoupling the already-existing disconnected bit (
MARK_BITintail) into the two: one for::drop()as was before, one for new::disconnect(), although this pr touches the heart of the impl unlike #959 (i.e. more intrusive....). Also, the almost all of existing code is already robust enough to introduce the 2 kinds of disconnected status. Come to think of it, {receivers, senders} should be able to cope with disconnected {senders, receivers} at any given moment of time due todrops.As for performance hit, it should be negligible because there's no additional operation at all. just
<< 2instead of<< 1in the performance sensitive code-path. Also, no space increse. There were design considerations.