fork download
  1. package main
  2.  
  3. import (
  4. "log"
  5. "math/rand"
  6. "os"
  7. "time"
  8. )
  9.  
  10. // Number of philosophers is simply the length of this list.
  11. // It is not otherwise fixed in the program.
  12. var ph = []string{"Aristotle", "Kant", "Spinoza", "Marx", "Russell"}
  13.  
  14. const nBites = 3 // number of times each philosopher eats
  15.  
  16. var fmt = log.New(os.Stdout, "", 0) // for thread-safe output
  17.  
  18. // This solution uses channels to implement synchronization.
  19. // Sent over channels are "forks."
  20. type fork byte
  21.  
  22. // A fork object in the program obviously models a physical fork in the
  23. // philosopher simulation. In the more general context of resource
  24. // sharing, the object would represent exclusive control of a resource.
  25. // A separate channel represents each fork place. Two philosophers
  26. // have access to each fork. The channels are buffered with capacity = 1,
  27. // representing a place for a single fork.
  28.  
  29. // Goroutine for philosopher actions. An instance is run for each
  30. // philosopher. Instances run concurrently.
  31. func philosopher(phName string,
  32. dominantHand, otherHand chan fork, done chan bool) {
  33. fmt.Println(phName, "seated")
  34. rg := rand.New(rand.NewSource(time.Now().UnixNano()))
  35. for i := 0; i < nBites; i++ {
  36. fmt.Println(phName, "hungry")
  37. <-dominantHand // pick up forks
  38. <-otherHand
  39. fmt.Println(phName, "eating")
  40. time.Sleep(time.Duration(rg.Int63n(1e8)))
  41. dominantHand <- 'f' // put down forks
  42. otherHand <- 'f'
  43. fmt.Println(phName, "thinking")
  44. time.Sleep(time.Duration(rg.Int63n(1e8)))
  45. }
  46. fmt.Println(phName, "satisfied")
  47. done <- true
  48. fmt.Println(phName, "left the table")
  49. }
  50.  
  51. func main() {
  52. fmt.Println("table empty")
  53. // Create fork channels and start philosopher goroutines,
  54. // supplying each goroutine with the appropriate channels
  55. done := make(chan bool)
  56. place0 := make(chan fork, 1)
  57. place0 <- 'f' // byte in channel represents a fork on the table.
  58. placeLeft := place0
  59. for i := 1; i < len(ph); i++ {
  60. placeRight := make(chan fork, 1)
  61. placeRight <- 'f'
  62. go philosopher(ph[i], placeLeft, placeRight, done)
  63. placeLeft = placeRight
  64. }
  65. // Make one philosopher left handed by reversing fork place
  66. // supplied to philosopher's dominant hand.
  67. // This makes precedence acyclic, preventing deadlock.
  68. go philosopher(ph[0], place0, placeLeft, done)
  69. // they are all now busy eating
  70. for _ = range ph {
  71. <-done // wait for philosphers to finish
  72. }
  73. fmt.Println("table empty")
  74. }
Success #stdin #stdout 0.01s 5280KB
stdin
Standard input is empty
stdout
table empty
Aristotle seated
Aristotle hungry
Aristotle eating
Kant seated
Kant hungry
Spinoza seated
Spinoza hungry
Spinoza eating
Marx seated
Marx hungry
Russell seated
Russell hungry
Aristotle thinking
Russell eating
Aristotle hungry
Russell thinking
Spinoza thinking
Marx eating
Kant eating
Kant thinking
Aristotle eating
Spinoza hungry
Aristotle thinking
Marx thinking
Spinoza eating
Russell hungry
Russell eating
Russell thinking
Kant hungry
Marx hungry
Aristotle hungry
Russell hungry
Russell eating
Spinoza thinking
Kant eating
Spinoza hungry
Kant thinking
Russell thinking
Aristotle eating
Marx eating
Russell satisfied
Russell left the table
Marx thinking
Spinoza eating
Marx hungry
Aristotle thinking
Kant hungry
Spinoza thinking
Marx eating
Kant eating
Marx thinking
Spinoza satisfied
Spinoza left the table
Kant thinking
Marx satisfied
Marx left the table
Aristotle satisfied
Aristotle left the table
Kant satisfied
Kant left the table
table empty