Puzzled by these golang issues with concurrency
I just finished the "Concurrency in go" course on coursera(https://www.coursera.org/learn/golang-concurrency/) and I really struggled with the last assignments. This is my submission:
// 1.There should be 5 philosophers sharing chopsticks, with one chopstick between each adjacent pair of philosophers.
// 2.Each philosopher should eat only 3 times (not in an infinite loop as we did in lecture)
// 3.The philosophers pick up the chopsticks in any order, not lowest-numbered first (which we did in lecture).
// 4.In order to eat, a philosopher must get permission from a host which executes in its own goroutine.
// 5.The host allows no more than 2 philosophers to eat concurrently.
// 6.Each philosopher is numbered, 1 through 5.
// 7.When a philosopher starts eating (after it has obtained necessary locks) it prints “starting to eat <number>” on a line by itself, where <number> is the number of the philosopher.
// 8.When a philosopher finishes eating (before it has released its locks) it prints “finishing eating <number>” on a line by itself, where <number> is the number of the philosopher.
package main
import (
"fmt"
"sync"
)
var eating = make(chan int, 2)
var mu sync.RWMutex
var everyoneAte int
var timesEaten = make(map[int]int, 5)
type chopstick struct {
sync.Mutex
}
type philosopher struct {
leftCs *chopstick
rightCs *chopstick
}
func alreadyAte(index int) bool {
mu.Lock()
defer mu.Unlock()
if timesEaten[index] == 3 {
return true
}
return false
}
func (p philosopher) eat(index int) {
eating <- 1
p.leftCs.Lock()
p.rightCs.Lock()
fmt.Printf("Starting to eat %vn", index)
fmt.Printf("Finishing eating %vn", index)
mu.Lock()
timesEaten[index]++
if timesEaten[index] == 3 {
everyoneAte++
}
mu.Unlock()
p.rightCs.Unlock()
p.leftCs.Unlock()
<-eating
}
func main() {
count := 5
chopsticks := make(*chopstick, count)
for i := 0; i < count; i++ {
chopsticks[i] = &chopstick{}
}
philosophers := make(*philosopher, count)
for i := 0; i < count; i++ {
philosophers[i] = &philosopher{
leftCs: chopsticks[i],
rightCs: chopsticks[(i+1)%count],
}
}
for {
mu.RLock()
if everyoneAte == count {
return
}
for i := 0; i < count; i++ {
if timesEaten[i] == 3 {
continue
}
go philosophers[i].eat(i + 1)
}
mu.RUnlock()
}
}
I did not understand how to implement #4 so I just used a buffered channel instead 🤷♂️
I don't understand why after returning, some philosophers have eaten more than 3 times 🙃
If everyone has answers to those questions, I would appreciate it. I've already submitted the assignment.
go concurrency
add a comment |
I just finished the "Concurrency in go" course on coursera(https://www.coursera.org/learn/golang-concurrency/) and I really struggled with the last assignments. This is my submission:
// 1.There should be 5 philosophers sharing chopsticks, with one chopstick between each adjacent pair of philosophers.
// 2.Each philosopher should eat only 3 times (not in an infinite loop as we did in lecture)
// 3.The philosophers pick up the chopsticks in any order, not lowest-numbered first (which we did in lecture).
// 4.In order to eat, a philosopher must get permission from a host which executes in its own goroutine.
// 5.The host allows no more than 2 philosophers to eat concurrently.
// 6.Each philosopher is numbered, 1 through 5.
// 7.When a philosopher starts eating (after it has obtained necessary locks) it prints “starting to eat <number>” on a line by itself, where <number> is the number of the philosopher.
// 8.When a philosopher finishes eating (before it has released its locks) it prints “finishing eating <number>” on a line by itself, where <number> is the number of the philosopher.
package main
import (
"fmt"
"sync"
)
var eating = make(chan int, 2)
var mu sync.RWMutex
var everyoneAte int
var timesEaten = make(map[int]int, 5)
type chopstick struct {
sync.Mutex
}
type philosopher struct {
leftCs *chopstick
rightCs *chopstick
}
func alreadyAte(index int) bool {
mu.Lock()
defer mu.Unlock()
if timesEaten[index] == 3 {
return true
}
return false
}
func (p philosopher) eat(index int) {
eating <- 1
p.leftCs.Lock()
p.rightCs.Lock()
fmt.Printf("Starting to eat %vn", index)
fmt.Printf("Finishing eating %vn", index)
mu.Lock()
timesEaten[index]++
if timesEaten[index] == 3 {
everyoneAte++
}
mu.Unlock()
p.rightCs.Unlock()
p.leftCs.Unlock()
<-eating
}
func main() {
count := 5
chopsticks := make(*chopstick, count)
for i := 0; i < count; i++ {
chopsticks[i] = &chopstick{}
}
philosophers := make(*philosopher, count)
for i := 0; i < count; i++ {
philosophers[i] = &philosopher{
leftCs: chopsticks[i],
rightCs: chopsticks[(i+1)%count],
}
}
for {
mu.RLock()
if everyoneAte == count {
return
}
for i := 0; i < count; i++ {
if timesEaten[i] == 3 {
continue
}
go philosophers[i].eat(i + 1)
}
mu.RUnlock()
}
}
I did not understand how to implement #4 so I just used a buffered channel instead 🤷♂️
I don't understand why after returning, some philosophers have eaten more than 3 times 🙃
If everyone has answers to those questions, I would appreciate it. I've already submitted the assignment.
go concurrency
add a comment |
I just finished the "Concurrency in go" course on coursera(https://www.coursera.org/learn/golang-concurrency/) and I really struggled with the last assignments. This is my submission:
// 1.There should be 5 philosophers sharing chopsticks, with one chopstick between each adjacent pair of philosophers.
// 2.Each philosopher should eat only 3 times (not in an infinite loop as we did in lecture)
// 3.The philosophers pick up the chopsticks in any order, not lowest-numbered first (which we did in lecture).
// 4.In order to eat, a philosopher must get permission from a host which executes in its own goroutine.
// 5.The host allows no more than 2 philosophers to eat concurrently.
// 6.Each philosopher is numbered, 1 through 5.
// 7.When a philosopher starts eating (after it has obtained necessary locks) it prints “starting to eat <number>” on a line by itself, where <number> is the number of the philosopher.
// 8.When a philosopher finishes eating (before it has released its locks) it prints “finishing eating <number>” on a line by itself, where <number> is the number of the philosopher.
package main
import (
"fmt"
"sync"
)
var eating = make(chan int, 2)
var mu sync.RWMutex
var everyoneAte int
var timesEaten = make(map[int]int, 5)
type chopstick struct {
sync.Mutex
}
type philosopher struct {
leftCs *chopstick
rightCs *chopstick
}
func alreadyAte(index int) bool {
mu.Lock()
defer mu.Unlock()
if timesEaten[index] == 3 {
return true
}
return false
}
func (p philosopher) eat(index int) {
eating <- 1
p.leftCs.Lock()
p.rightCs.Lock()
fmt.Printf("Starting to eat %vn", index)
fmt.Printf("Finishing eating %vn", index)
mu.Lock()
timesEaten[index]++
if timesEaten[index] == 3 {
everyoneAte++
}
mu.Unlock()
p.rightCs.Unlock()
p.leftCs.Unlock()
<-eating
}
func main() {
count := 5
chopsticks := make(*chopstick, count)
for i := 0; i < count; i++ {
chopsticks[i] = &chopstick{}
}
philosophers := make(*philosopher, count)
for i := 0; i < count; i++ {
philosophers[i] = &philosopher{
leftCs: chopsticks[i],
rightCs: chopsticks[(i+1)%count],
}
}
for {
mu.RLock()
if everyoneAte == count {
return
}
for i := 0; i < count; i++ {
if timesEaten[i] == 3 {
continue
}
go philosophers[i].eat(i + 1)
}
mu.RUnlock()
}
}
I did not understand how to implement #4 so I just used a buffered channel instead 🤷♂️
I don't understand why after returning, some philosophers have eaten more than 3 times 🙃
If everyone has answers to those questions, I would appreciate it. I've already submitted the assignment.
go concurrency
I just finished the "Concurrency in go" course on coursera(https://www.coursera.org/learn/golang-concurrency/) and I really struggled with the last assignments. This is my submission:
// 1.There should be 5 philosophers sharing chopsticks, with one chopstick between each adjacent pair of philosophers.
// 2.Each philosopher should eat only 3 times (not in an infinite loop as we did in lecture)
// 3.The philosophers pick up the chopsticks in any order, not lowest-numbered first (which we did in lecture).
// 4.In order to eat, a philosopher must get permission from a host which executes in its own goroutine.
// 5.The host allows no more than 2 philosophers to eat concurrently.
// 6.Each philosopher is numbered, 1 through 5.
// 7.When a philosopher starts eating (after it has obtained necessary locks) it prints “starting to eat <number>” on a line by itself, where <number> is the number of the philosopher.
// 8.When a philosopher finishes eating (before it has released its locks) it prints “finishing eating <number>” on a line by itself, where <number> is the number of the philosopher.
package main
import (
"fmt"
"sync"
)
var eating = make(chan int, 2)
var mu sync.RWMutex
var everyoneAte int
var timesEaten = make(map[int]int, 5)
type chopstick struct {
sync.Mutex
}
type philosopher struct {
leftCs *chopstick
rightCs *chopstick
}
func alreadyAte(index int) bool {
mu.Lock()
defer mu.Unlock()
if timesEaten[index] == 3 {
return true
}
return false
}
func (p philosopher) eat(index int) {
eating <- 1
p.leftCs.Lock()
p.rightCs.Lock()
fmt.Printf("Starting to eat %vn", index)
fmt.Printf("Finishing eating %vn", index)
mu.Lock()
timesEaten[index]++
if timesEaten[index] == 3 {
everyoneAte++
}
mu.Unlock()
p.rightCs.Unlock()
p.leftCs.Unlock()
<-eating
}
func main() {
count := 5
chopsticks := make(*chopstick, count)
for i := 0; i < count; i++ {
chopsticks[i] = &chopstick{}
}
philosophers := make(*philosopher, count)
for i := 0; i < count; i++ {
philosophers[i] = &philosopher{
leftCs: chopsticks[i],
rightCs: chopsticks[(i+1)%count],
}
}
for {
mu.RLock()
if everyoneAte == count {
return
}
for i := 0; i < count; i++ {
if timesEaten[i] == 3 {
continue
}
go philosophers[i].eat(i + 1)
}
mu.RUnlock()
}
}
I did not understand how to implement #4 so I just used a buffered channel instead 🤷♂️
I don't understand why after returning, some philosophers have eaten more than 3 times 🙃
If everyone has answers to those questions, I would appreciate it. I've already submitted the assignment.
go concurrency
go concurrency
asked Nov 22 '18 at 20:45
scuttle-jesuitscuttle-jesuit
1298
1298
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
Here is the sequence where philosophers might eat more than three times
Assume philosopher_1 has eaten 2 times
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat on a separate goroutine_1 - main: releases
RLock
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat again on a separate goroutine_2 - main: releases
RLock
- goroutine_1: acquires
Lock
- goroutine_1: sets
timesEaten[1] = 3
- goroutine_1: releases
Lock
- goroutine_2: acquires
Lock
- goroutine_2: sets
timesEaten[1] = 4
<--philosopher_1
ate more than 3 times - goroutine_2: releases
Lock
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%2f53437791%2fpuzzled-by-these-golang-issues-with-concurrency%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
Here is the sequence where philosophers might eat more than three times
Assume philosopher_1 has eaten 2 times
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat on a separate goroutine_1 - main: releases
RLock
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat again on a separate goroutine_2 - main: releases
RLock
- goroutine_1: acquires
Lock
- goroutine_1: sets
timesEaten[1] = 3
- goroutine_1: releases
Lock
- goroutine_2: acquires
Lock
- goroutine_2: sets
timesEaten[1] = 4
<--philosopher_1
ate more than 3 times - goroutine_2: releases
Lock
add a comment |
Here is the sequence where philosophers might eat more than three times
Assume philosopher_1 has eaten 2 times
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat on a separate goroutine_1 - main: releases
RLock
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat again on a separate goroutine_2 - main: releases
RLock
- goroutine_1: acquires
Lock
- goroutine_1: sets
timesEaten[1] = 3
- goroutine_1: releases
Lock
- goroutine_2: acquires
Lock
- goroutine_2: sets
timesEaten[1] = 4
<--philosopher_1
ate more than 3 times - goroutine_2: releases
Lock
add a comment |
Here is the sequence where philosophers might eat more than three times
Assume philosopher_1 has eaten 2 times
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat on a separate goroutine_1 - main: releases
RLock
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat again on a separate goroutine_2 - main: releases
RLock
- goroutine_1: acquires
Lock
- goroutine_1: sets
timesEaten[1] = 3
- goroutine_1: releases
Lock
- goroutine_2: acquires
Lock
- goroutine_2: sets
timesEaten[1] = 4
<--philosopher_1
ate more than 3 times - goroutine_2: releases
Lock
Here is the sequence where philosophers might eat more than three times
Assume philosopher_1 has eaten 2 times
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat on a separate goroutine_1 - main: releases
RLock
- main: acquires
RLock
- main: reads
timesEaten[1] == 2
- main: makes
philosopher_1
eat again on a separate goroutine_2 - main: releases
RLock
- goroutine_1: acquires
Lock
- goroutine_1: sets
timesEaten[1] = 3
- goroutine_1: releases
Lock
- goroutine_2: acquires
Lock
- goroutine_2: sets
timesEaten[1] = 4
<--philosopher_1
ate more than 3 times - goroutine_2: releases
Lock
answered Nov 23 '18 at 3:46
ssemillassemilla
3,087424
3,087424
add a comment |
add a comment |
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%2f53437791%2fpuzzled-by-these-golang-issues-with-concurrency%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