memory leak in solution for Exercise: Equivalent Binary Trees?How does select work when multiple channels are involved?Anatomy of a “Memory Leak”Are memory leaks ever ok?Creating a memory leak with JavaGo Tour Exercise: Equivalent Binary TreesHow to check a channel is closed or not without reading it?Using multiple Goroutines on Go Tour Equivalent Binary TreesGolang channels using select doesn't stopHow to stop a goroutine that is listening for RethinkDB changefeeds?two way communication through channels in golangSignal goroutines to stop with channel close
How do you name this compound using IUPAC system (including steps)?
Could Europeans in Europe demand protection under UN Declaration on the Rights of Indigenous Peoples?
Integration using partial fraction is wrong
Are there any satellites in geosynchronous but not geostationary orbits?
Are there foods that astronauts are explicitly never allowed to eat?
How to tell readers that I know my story is factually incorrect?
Applying for jobs with an obvious scar
What's a German word for »Sandbagger«?
"Je suis petite, moi?", purpose of the "moi"?
How do you send money when you're not sure it's not a scam?
How to belay quickly ascending top-rope climbers?
A spacecraft is travelling at X units per hour. But relative to what exactly? Does it depend on orbit? How?
Company looks for long-term employees, but I know I won't be interested in staying long
Project Euler # 25 The 1000 digit Fibonacci index
Why are flying carpets banned while flying brooms are not?
Do Australia and New Zealand have a travel ban on Somalis (like Wikipedia says)?
Transistor power dissipation rating
Why would word of Princess Leia's capture generate sympathy for the Rebellion in the Senate?
Authorship dispute on a paper that came out of a final report of a course?
Equality of complex numbers in general
How did Jayne know when to shoot?
How can I automate this tensor computation?
Why does a tetrahedral molecule like methane have a dipole moment of zero?
Why is regex [0-9]0,2 not greedy in sed?
memory leak in solution for Exercise: Equivalent Binary Trees?
How does select work when multiple channels are involved?Anatomy of a “Memory Leak”Are memory leaks ever ok?Creating a memory leak with JavaGo Tour Exercise: Equivalent Binary TreesHow to check a channel is closed or not without reading it?Using multiple Goroutines on Go Tour Equivalent Binary TreesGolang channels using select doesn't stopHow to stop a goroutine that is listening for RethinkDB changefeeds?two way communication through channels in golangSignal goroutines to stop with channel close
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
(https://github.com/golang/tour/blob/master/solutions/binarytrees_quit.go) for Exercise: Equivalent Binary Trees
Supposed we have two simple equivalent binary trees "1 3 5" and "2 3 5". When two goroutines "Walk" walks at leaf "1" and "2" concurrently,
if v1 != v2
return false
this condition in function Same will be true and
close(quit)
will run.
func walkImpl(t *tree.Tree, ch, quit chan int)
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Channel "quit" will receive message and the second case of select statement will execute. And then it will go back to the upper level function "walkImpl" and keep on running the last line walkImpl(t.Right, ch, quit). So is there goroutine leak under the circumstance, cause channel "quit" is already read out, which can't be read again in the upper level? Function "Walk" also can't go back to "close" handler.
go memory-leaks
add a comment |
(https://github.com/golang/tour/blob/master/solutions/binarytrees_quit.go) for Exercise: Equivalent Binary Trees
Supposed we have two simple equivalent binary trees "1 3 5" and "2 3 5". When two goroutines "Walk" walks at leaf "1" and "2" concurrently,
if v1 != v2
return false
this condition in function Same will be true and
close(quit)
will run.
func walkImpl(t *tree.Tree, ch, quit chan int)
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Channel "quit" will receive message and the second case of select statement will execute. And then it will go back to the upper level function "walkImpl" and keep on running the last line walkImpl(t.Right, ch, quit). So is there goroutine leak under the circumstance, cause channel "quit" is already read out, which can't be read again in the upper level? Function "Walk" also can't go back to "close" handler.
go memory-leaks
add a comment |
(https://github.com/golang/tour/blob/master/solutions/binarytrees_quit.go) for Exercise: Equivalent Binary Trees
Supposed we have two simple equivalent binary trees "1 3 5" and "2 3 5". When two goroutines "Walk" walks at leaf "1" and "2" concurrently,
if v1 != v2
return false
this condition in function Same will be true and
close(quit)
will run.
func walkImpl(t *tree.Tree, ch, quit chan int)
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Channel "quit" will receive message and the second case of select statement will execute. And then it will go back to the upper level function "walkImpl" and keep on running the last line walkImpl(t.Right, ch, quit). So is there goroutine leak under the circumstance, cause channel "quit" is already read out, which can't be read again in the upper level? Function "Walk" also can't go back to "close" handler.
go memory-leaks
(https://github.com/golang/tour/blob/master/solutions/binarytrees_quit.go) for Exercise: Equivalent Binary Trees
Supposed we have two simple equivalent binary trees "1 3 5" and "2 3 5". When two goroutines "Walk" walks at leaf "1" and "2" concurrently,
if v1 != v2
return false
this condition in function Same will be true and
close(quit)
will run.
func walkImpl(t *tree.Tree, ch, quit chan int)
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Channel "quit" will receive message and the second case of select statement will execute. And then it will go back to the upper level function "walkImpl" and keep on running the last line walkImpl(t.Right, ch, quit). So is there goroutine leak under the circumstance, cause channel "quit" is already read out, which can't be read again in the upper level? Function "Walk" also can't go back to "close" handler.
go memory-leaks
go memory-leaks
edited Mar 26 at 11:05
Flimzy
43.5k13 gold badges71 silver badges109 bronze badges
43.5k13 gold badges71 silver badges109 bronze badges
asked Mar 26 at 11:03
Yu LiuYu Liu
182 bronze badges
182 bronze badges
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
When multiple goroutines are targeted with a cancellation signal, most often it is done by closing a channel, and not sending a value on the channel. Receiving from a closed channel can proceed immediately, no matter how many goroutines do that. A value sent on a channel can be received at most once, so it is not suitable to signal multiple goroutines with a value. Spec: Receive operator:
A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.
Now, if you close the quit channel, that does not guarantee your function will return immediately.
First, you recurse down to the left child without checking quit, which call will do the same (until a nil left child is reached).
Second, if a value can be sent on ch, then both cases are ready and thus select chooses one of them randomly, which may or may not be the quit case. For details, see How does select work when multiple channels are involved?
If you want to avoid these, you should add a non-blocking quit check as the first thing in your function:
func walkImpl(t *tree.Tree, ch, quit chan int)
select
case <-quit:
return
default: // This empty default makes it a non-blocking check
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Now one could ask if we still need the quit case in the second select since we've already checked it first thing in walkImpl(). The answer is that you should keep that too, because if sending on ch would block (e.g. the consumer would be shut down when quit is closed), that send operation could block forever. This way (when quit is closed) it is guaranteed that the function returns.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55355577%2fmemory-leak-in-solution-for-exercise-equivalent-binary-trees%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
When multiple goroutines are targeted with a cancellation signal, most often it is done by closing a channel, and not sending a value on the channel. Receiving from a closed channel can proceed immediately, no matter how many goroutines do that. A value sent on a channel can be received at most once, so it is not suitable to signal multiple goroutines with a value. Spec: Receive operator:
A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.
Now, if you close the quit channel, that does not guarantee your function will return immediately.
First, you recurse down to the left child without checking quit, which call will do the same (until a nil left child is reached).
Second, if a value can be sent on ch, then both cases are ready and thus select chooses one of them randomly, which may or may not be the quit case. For details, see How does select work when multiple channels are involved?
If you want to avoid these, you should add a non-blocking quit check as the first thing in your function:
func walkImpl(t *tree.Tree, ch, quit chan int)
select
case <-quit:
return
default: // This empty default makes it a non-blocking check
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Now one could ask if we still need the quit case in the second select since we've already checked it first thing in walkImpl(). The answer is that you should keep that too, because if sending on ch would block (e.g. the consumer would be shut down when quit is closed), that send operation could block forever. This way (when quit is closed) it is guaranteed that the function returns.
add a comment |
When multiple goroutines are targeted with a cancellation signal, most often it is done by closing a channel, and not sending a value on the channel. Receiving from a closed channel can proceed immediately, no matter how many goroutines do that. A value sent on a channel can be received at most once, so it is not suitable to signal multiple goroutines with a value. Spec: Receive operator:
A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.
Now, if you close the quit channel, that does not guarantee your function will return immediately.
First, you recurse down to the left child without checking quit, which call will do the same (until a nil left child is reached).
Second, if a value can be sent on ch, then both cases are ready and thus select chooses one of them randomly, which may or may not be the quit case. For details, see How does select work when multiple channels are involved?
If you want to avoid these, you should add a non-blocking quit check as the first thing in your function:
func walkImpl(t *tree.Tree, ch, quit chan int)
select
case <-quit:
return
default: // This empty default makes it a non-blocking check
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Now one could ask if we still need the quit case in the second select since we've already checked it first thing in walkImpl(). The answer is that you should keep that too, because if sending on ch would block (e.g. the consumer would be shut down when quit is closed), that send operation could block forever. This way (when quit is closed) it is guaranteed that the function returns.
add a comment |
When multiple goroutines are targeted with a cancellation signal, most often it is done by closing a channel, and not sending a value on the channel. Receiving from a closed channel can proceed immediately, no matter how many goroutines do that. A value sent on a channel can be received at most once, so it is not suitable to signal multiple goroutines with a value. Spec: Receive operator:
A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.
Now, if you close the quit channel, that does not guarantee your function will return immediately.
First, you recurse down to the left child without checking quit, which call will do the same (until a nil left child is reached).
Second, if a value can be sent on ch, then both cases are ready and thus select chooses one of them randomly, which may or may not be the quit case. For details, see How does select work when multiple channels are involved?
If you want to avoid these, you should add a non-blocking quit check as the first thing in your function:
func walkImpl(t *tree.Tree, ch, quit chan int)
select
case <-quit:
return
default: // This empty default makes it a non-blocking check
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Now one could ask if we still need the quit case in the second select since we've already checked it first thing in walkImpl(). The answer is that you should keep that too, because if sending on ch would block (e.g. the consumer would be shut down when quit is closed), that send operation could block forever. This way (when quit is closed) it is guaranteed that the function returns.
When multiple goroutines are targeted with a cancellation signal, most often it is done by closing a channel, and not sending a value on the channel. Receiving from a closed channel can proceed immediately, no matter how many goroutines do that. A value sent on a channel can be received at most once, so it is not suitable to signal multiple goroutines with a value. Spec: Receive operator:
A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.
Now, if you close the quit channel, that does not guarantee your function will return immediately.
First, you recurse down to the left child without checking quit, which call will do the same (until a nil left child is reached).
Second, if a value can be sent on ch, then both cases are ready and thus select chooses one of them randomly, which may or may not be the quit case. For details, see How does select work when multiple channels are involved?
If you want to avoid these, you should add a non-blocking quit check as the first thing in your function:
func walkImpl(t *tree.Tree, ch, quit chan int)
select
case <-quit:
return
default: // This empty default makes it a non-blocking check
if t == nil
return
walkImpl(t.Left, ch, quit)
select
case ch <- t.Value:
// Value successfully sent.
case <-quit:
return
walkImpl(t.Right, ch, quit)
Now one could ask if we still need the quit case in the second select since we've already checked it first thing in walkImpl(). The answer is that you should keep that too, because if sending on ch would block (e.g. the consumer would be shut down when quit is closed), that send operation could block forever. This way (when quit is closed) it is guaranteed that the function returns.
edited Mar 26 at 13:14
answered Mar 26 at 12:03
iczaicza
192k28 gold badges404 silver badges423 bronze badges
192k28 gold badges404 silver badges423 bronze badges
add a comment |
add a comment |
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Got a question that you can’t ask on public Stack Overflow? Learn more about sharing private information with Stack Overflow for Teams.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55355577%2fmemory-leak-in-solution-for-exercise-equivalent-binary-trees%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown