Golang中如何解决哲学家就餐问题
Golang中如何解决哲学家就餐问题 我正在研究哲学家就餐问题程序
应该有5位哲学家共享筷子,每对相邻哲学家之间有一根筷子。 每位哲学家只能进食3次 哲学家可以按任意顺序拿起筷子,不需要先拿编号最小的 要进食时,哲学家必须从在自己例程中运行的主机获得许可。 主机不允许超过2位哲学家同时进食。 每位哲学家的编号从1到5。 当哲学家开始进食时(在获得必要的锁之后),打印一行"开始进食 ",其中是哲学家的编号。 当哲学家结束进食时(在释放锁之前),打印一行"结束进食 ",其中是哲学家的编号。
type ChopS struct{ sync.Mutex }
type Philo struct {
leftCS, rightCS * ChopS
}
//Eat
func (p Philo) eat() {
for {
p.leftCS.Lock()
p.rightCS.Lock()
fmt.Println("eating")
p.rightCS.Unlock()
p.leftCS.Unlock()
}
}
//main
CSticks := make([]*ChopS, 5)
for i := 0; i < 5; i++ {
CSticks[i] = new(ChopS)
}
philos := make([]*Philo, 5)
for i := 0; i < 5; i++ {
philos[i] = &Philo{Csticks[i], Csticks[(i+1)%5]}
}
CSticks := make([]*ChopS, 5)
for i := 0; i < 5; i++ {
CSticks[i] = new(ChopS)
}
philos := make([]*Philo, 5)
for i := 0; i < 5; i++ {
philos[i] = &Philo{Csticks[i], Csticks[(i+1)%5]}
}
// cena main
for i := 0; i < 5; i++ {
go philos[i].eat()
}
//comida
p.leftCS.Lock()
p.rightCS.Lock()
fmt.Println("eating")
p.rightCS.Unlock()
p.leftCS.Unlock()
更多关于Golang中如何解决哲学家就餐问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
更多关于Golang中如何解决哲学家就餐问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
以下是针对哲学家就餐问题的Go语言实现,修正了原始代码中的问题并满足所有要求。这个解决方案使用信号量来控制同时进食的哲学家数量,并确保不会发生死锁。
package main
import (
"fmt"
"sync"
"time"
)
type ChopS struct{ sync.Mutex }
type Philo struct {
id int
leftCS, rightCS *ChopS
eatCount int
}
type Host struct {
eatingSem chan struct{}
}
func (h *Host) requestPermission() {
h.eatingSem <- struct{}{}
}
func (h *Host) releasePermission() {
<-h.eatingSem
}
func (p *Philo) eat(host *Host, wg *sync.WaitGroup) {
defer wg.Done()
for p.eatCount < 3 {
// 请求主机许可
host.requestPermission()
// 拿起筷子(可以按任意顺序)
p.leftCS.Lock()
p.rightCS.Lock()
// 开始进食
fmt.Printf("开始进食 %d\n", p.id)
time.Sleep(100 * time.Millisecond) // 模拟进食时间
// 结束进食
fmt.Printf("结束进食 %d\n", p.id)
p.eatCount++
// 放下筷子
p.rightCS.Unlock()
p.leftCS.Unlock()
// 释放主机许可
host.releasePermission()
time.Sleep(100 * time.Millisecond) // 思考时间
}
}
func main() {
// 初始化5根筷子
CSticks := make([]*ChopS, 5)
for i := 0; i < 5; i++ {
CSticks[i] = new(ChopS)
}
// 初始化主机,限制最多2个哲学家同时进食
host := &Host{
eatingSem: make(chan struct{}, 2),
}
// 初始化5位哲学家
philos := make([]*Philo, 5)
for i := 0; i < 5; i++ {
philos[i] = &Philo{
id: i + 1,
leftCS: CSticks[i],
rightCS: CSticks[(i+1)%5],
eatCount: 0,
}
}
// 使用WaitGroup等待所有哲学家完成进食
var wg sync.WaitGroup
// 启动所有哲学家的goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go philos[i].eat(host, &wg)
}
// 等待所有哲学家完成3次进食
wg.Wait()
fmt.Println("所有哲学家都完成了3次进食")
}
这个实现的关键特性:
- 主机控制:使用带缓冲的channel作为信号量,限制最多2个哲学家同时进食
- 死锁避免:通过主机许可机制防止所有哲学家同时拿起筷子导致的死锁
- 进食次数限制:每个哲学家只进食3次
- 正确的锁顺序:每个哲学家按任意顺序拿起筷子(先左后右或先右后左都可以)
- 正确的输出:在获得锁之后打印"开始进食",在释放锁之前打印"结束进食"
运行这个程序,你会看到类似以下的输出:
开始进食 1
开始进食 2
结束进食 1
结束进食 2
开始进食 3
开始进食 4
结束进食 3
结束进食 4
开始进食 5
...
所有哲学家都完成了3次进食
这个解决方案确保了所有要求都被满足,包括并发控制、资源管理和正确的输出格式。

