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 Bridge 🚀🎆

你遇到的情况和之前你同学遇到的问题完全一样:链接

随时关注他/她的发现进展。

更多关于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次进食")
}

这个实现的关键特性:

  1. 主机控制:使用带缓冲的channel作为信号量,限制最多2个哲学家同时进食
  2. 死锁避免:通过主机许可机制防止所有哲学家同时拿起筷子导致的死锁
  3. 进食次数限制:每个哲学家只进食3次
  4. 正确的锁顺序:每个哲学家按任意顺序拿起筷子(先左后右或先右后左都可以)
  5. 正确的输出:在获得锁之后打印"开始进食",在释放锁之前打印"结束进食"

运行这个程序,你会看到类似以下的输出:

开始进食 1
开始进食 2
结束进食 1
结束进食 2
开始进食 3
开始进食 4
结束进食 3
结束进食 4
开始进食 5
...
所有哲学家都完成了3次进食

这个解决方案确保了所有要求都被满足,包括并发控制、资源管理和正确的输出格式。

回到顶部