-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Fluid channels should match the semantics of Go Channels #9265
Changes from 4 commits
3ea2a51
f0a32dc
02efae5
59382b7
81ca62f
654619a
7b64d62
621e4a8
2877691
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ class ChannelImpl : public paddle::framework::Channel<T> { | |
public: | ||
virtual bool CanSend(); | ||
virtual bool CanReceive(); | ||
virtual bool Send(T *); | ||
virtual void Send(T *); | ||
virtual bool Receive(T *); | ||
virtual size_t Cap() { return cap_; } | ||
virtual void Lock(); | ||
|
@@ -76,10 +76,9 @@ class ChannelImpl : public paddle::framework::Channel<T> { | |
} | ||
}; | ||
|
||
bool send_return(bool value) { | ||
void send_return() { | ||
send_ctr--; | ||
destructor_cond_.notify_all(); | ||
return value; | ||
} | ||
|
||
bool recv_return(bool value) { | ||
|
@@ -118,15 +117,15 @@ bool ChannelImpl<T>::CanReceive() { | |
} | ||
|
||
template <typename T> | ||
bool ChannelImpl<T>::Send(T *item) { | ||
void ChannelImpl<T>::Send(T *item) { | ||
send_ctr++; | ||
std::unique_lock<std::recursive_mutex> lock{mu_}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to explicitly lock after constructor? lock->lock() ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No we don't need to do that. The unique lock constructor automatically does that. |
||
|
||
// If channel is closed, do nothing | ||
// If channel is closed, throw exception | ||
if (closed_) { | ||
lock.unlock(); | ||
// TODO(abhinavarora) Should panic on closed channel | ||
return send_return(false); | ||
send_return(); | ||
PADDLE_THROW("Cannot send on closed channel"); | ||
} | ||
|
||
// If there is a receiver, directly pass the value we want | ||
|
@@ -143,20 +142,24 @@ bool ChannelImpl<T>::Send(T *item) { | |
if (m->callback != nullptr) do_send = m->callback(ChannelAction::SEND); | ||
if (do_send) | ||
*(m->data) = std::move(*item); | ||
else | ||
else { | ||
// We cannot do the data transfer because | ||
// this QueueMessage was added by Select | ||
// and some other case was executed. | ||
// So call the Send function again. | ||
// We do not care about notifying other | ||
// because they would have been notified | ||
// by the executed select case. | ||
return send_return(Send(item)); | ||
Send(item); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to "lock.unlock();" here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you are right, it makes sense to release the lock there. With the new semantics if the nested method call leads to an exception then the outer lock will be held forever. |
||
send_return(); | ||
return; | ||
} | ||
|
||
// Wake up the blocked process and unlock | ||
m->Notify(); | ||
lock.unlock(); | ||
return send_return(true); | ||
send_return(); | ||
return; | ||
} | ||
|
||
// Unbuffered channel will always bypass this | ||
|
@@ -167,16 +170,20 @@ bool ChannelImpl<T>::Send(T *item) { | |
buf_.push_back(std::move(*item)); | ||
// Release lock and return true | ||
lock.unlock(); | ||
return send_return(true); | ||
send_return(); | ||
return; | ||
} | ||
|
||
// Block on channel, because some receiver will complete | ||
// the operation for us | ||
auto m = std::make_shared<QueueMessage>(item); | ||
sendq.push_back(m); | ||
m->Wait(lock); | ||
// TODO(abhinavarora) Should panic on closed channel | ||
return send_return(!m->chan_closed); | ||
if (m->chan_closed) { | ||
send_return(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should unlock before throwing exception |
||
PADDLE_THROW("Cannot send on closed channel"); | ||
} | ||
send_return(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to unlock here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, the lock needs to be unlocked here. Thank you for pointing this out. |
||
} | ||
|
||
template <typename T> | ||
|
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 It is better that adding exception information for
PADDLE_ENFORCE_EQ
,e.g.
PADDLE_ENFORCE_EQ(IsInitialized(), true, "The channel hasn't been initialized.");
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.
Done