go - 对这些 golang 并发问题感到困惑
问题描述
我刚刚完成了 coursera ( https://www.coursera.org/learn/golang-concurrency/ ) 上的“Go 并发”课程,最后的作业我真的很挣扎。这是我的提交:
// 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 %v\n", index)
fmt.Printf("Finishing eating %v\n", 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()
}
}
我不明白如何实现#4,所以我只使用了缓冲通道 ♂️</p>
不明白为什么有些哲人回来后吃了3次以上
如果每个人都有这些问题的答案,我将不胜感激。我已经提交了作业。
解决方案
这是哲学家可能吃三遍以上的顺序
假设哲学家_1 已经吃过 2 次
- 主要:获取
RLock
- 主要:读
timesEaten[1] == 2
- main:
philosopher_1
在一个单独的 goroutine_1 上做吃 - 主要:发布
RLock
- 主要:获取
RLock
- 主要:读
timesEaten[1] == 2
- main:
philosopher_1
在一个单独的 goroutine_2 上再次进食 - 主要:发布
RLock
- goroutine_1:获取
Lock
- goroutine_1:设置
timesEaten[1] = 3
- goroutine_1:发布
Lock
- goroutine_2:获取
Lock
- goroutine_2: 设置
timesEaten[1] = 4
<--philosopher_1
吃了超过 3 次 - goroutine_2:发布
Lock
推荐阅读
- php - HTML 输入是否可以包含多个 DB 列名,(如果数据不在 x 列中,请检查 y 列)
- python - 如何在python中使用来自csv文件的数据
- javascript - 替换页面上所有出现的 vuejs
- c - 箭头运算符到静态非成员函数
- selenium - 元素在点 (80, 82) 处不可点击。其他元素会收到点击
- azure - 替换 Azure.Storage 中的 ListBlob 以遍历容器和 Blob
- javascript - ChartJS 2.9.3 在曲线经过轴时更改背景颜色
- jupyter-notebook - Jupyter nbconvert:扩展reveal.js;在标题中添加样式和脚本
- machine-learning - 我创建了一个 ResNet 模型,但损失并没有在训练中下降
- linux - Bash:动态使用 IFS=':' 从数组中读取多个值