Puzzled by these golang issues with concurrency












0















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.










share|improve this question



























    0















    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.










    share|improve this question

























      0












      0








      0








      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.










      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 22 '18 at 20:45









      scuttle-jesuitscuttle-jesuit

      1298




      1298
























          1 Answer
          1






          active

          oldest

          votes


















          1














          Here is the sequence where philosophers might eat more than three times



          Assume philosopher_1 has eaten 2 times




          1. main: acquires RLock

          2. main: reads timesEaten[1] == 2

          3. main: makes philosopher_1 eat on a separate goroutine_1

          4. main: releases RLock

          5. main: acquires RLock

          6. main: reads timesEaten[1] == 2

          7. main: makes philosopher_1 eat again on a separate goroutine_2

          8. main: releases RLock

          9. goroutine_1: acquires Lock

          10. goroutine_1: sets timesEaten[1] = 3

          11. goroutine_1: releases Lock

          12. goroutine_2: acquires Lock

          13. goroutine_2: sets timesEaten[1] = 4 <-- philosopher_1 ate more than 3 times

          14. goroutine_2: releases Lock






          share|improve this answer























            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
            });


            }
            });














            draft saved

            draft discarded


















            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









            1














            Here is the sequence where philosophers might eat more than three times



            Assume philosopher_1 has eaten 2 times




            1. main: acquires RLock

            2. main: reads timesEaten[1] == 2

            3. main: makes philosopher_1 eat on a separate goroutine_1

            4. main: releases RLock

            5. main: acquires RLock

            6. main: reads timesEaten[1] == 2

            7. main: makes philosopher_1 eat again on a separate goroutine_2

            8. main: releases RLock

            9. goroutine_1: acquires Lock

            10. goroutine_1: sets timesEaten[1] = 3

            11. goroutine_1: releases Lock

            12. goroutine_2: acquires Lock

            13. goroutine_2: sets timesEaten[1] = 4 <-- philosopher_1 ate more than 3 times

            14. goroutine_2: releases Lock






            share|improve this answer




























              1














              Here is the sequence where philosophers might eat more than three times



              Assume philosopher_1 has eaten 2 times




              1. main: acquires RLock

              2. main: reads timesEaten[1] == 2

              3. main: makes philosopher_1 eat on a separate goroutine_1

              4. main: releases RLock

              5. main: acquires RLock

              6. main: reads timesEaten[1] == 2

              7. main: makes philosopher_1 eat again on a separate goroutine_2

              8. main: releases RLock

              9. goroutine_1: acquires Lock

              10. goroutine_1: sets timesEaten[1] = 3

              11. goroutine_1: releases Lock

              12. goroutine_2: acquires Lock

              13. goroutine_2: sets timesEaten[1] = 4 <-- philosopher_1 ate more than 3 times

              14. goroutine_2: releases Lock






              share|improve this answer


























                1












                1








                1







                Here is the sequence where philosophers might eat more than three times



                Assume philosopher_1 has eaten 2 times




                1. main: acquires RLock

                2. main: reads timesEaten[1] == 2

                3. main: makes philosopher_1 eat on a separate goroutine_1

                4. main: releases RLock

                5. main: acquires RLock

                6. main: reads timesEaten[1] == 2

                7. main: makes philosopher_1 eat again on a separate goroutine_2

                8. main: releases RLock

                9. goroutine_1: acquires Lock

                10. goroutine_1: sets timesEaten[1] = 3

                11. goroutine_1: releases Lock

                12. goroutine_2: acquires Lock

                13. goroutine_2: sets timesEaten[1] = 4 <-- philosopher_1 ate more than 3 times

                14. goroutine_2: releases Lock






                share|improve this answer













                Here is the sequence where philosophers might eat more than three times



                Assume philosopher_1 has eaten 2 times




                1. main: acquires RLock

                2. main: reads timesEaten[1] == 2

                3. main: makes philosopher_1 eat on a separate goroutine_1

                4. main: releases RLock

                5. main: acquires RLock

                6. main: reads timesEaten[1] == 2

                7. main: makes philosopher_1 eat again on a separate goroutine_2

                8. main: releases RLock

                9. goroutine_1: acquires Lock

                10. goroutine_1: sets timesEaten[1] = 3

                11. goroutine_1: releases Lock

                12. goroutine_2: acquires Lock

                13. goroutine_2: sets timesEaten[1] = 4 <-- philosopher_1 ate more than 3 times

                14. goroutine_2: releases Lock







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 23 '18 at 3:46









                ssemillassemilla

                3,087424




                3,087424






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Wiesbaden

                    Marschland

                    Dieringhausen