-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce disconnection state for channels #1114
base: master
Are you sure you want to change the base?
Conversation
pub fn disconnect(&self) -> bool { | ||
match &self.flavor { | ||
SenderFlavor::List(chan) => chan.disconnect(), | ||
_ => todo!(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
|
||
if tail & MARK_BIT == 0 { | ||
if tail & TAIL_DISCONNECT_ANY == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, remove this empty line later....
@@ -628,13 +662,13 @@ impl<T> Channel<T> { | |||
drop(Box::from_raw(block)); | |||
} | |||
} | |||
head &= !MARK_BIT; | |||
head &= !HEAD_NOT_LAST; | |||
self.head.index.store(head, Ordering::Release); | |||
} | |||
|
|||
/// Returns `true` if the channel is disconnected. | |||
pub(crate) fn is_disconnected(&self) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: rename to reconnect()
?
@@ -580,3 +580,84 @@ fn channel_through_channel() { | |||
}) | |||
.unwrap(); | |||
} | |||
|
|||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(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. |
bump @taiki-e |
(hopefully) much improved pr than #959 ....
Currently,
crossbeam-channel
completely 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_sender
to 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_BIT
intail
) 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 todrop
s.As for performance hit, it should be negligible because there's no additional operation at all. just
<< 2
instead of<< 1
in the performance sensitive code-path. Also, no space increse. There were design considerations.