经典进程同步问题Go语言实现:哲学家问题

问题描述

五个哲学家共用一张圆桌,桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左右筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件
(1)只有拿到两只筷子时,哲学家才能吃饭;
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子;
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。

解决方法

使用state数组跟踪每个哲学家的状态(进餐、饥饿、思考)。

**饥饿状态:**哲学家在饥饿状态下试图拿筷子,需要读取周围邻居的状态,只有在两个邻居都没有进餐时才能同时拿到两边的筷子,进入进餐状态。就显然此时需要通过互斥锁保证读取的状态是不变的。若满足上述条件,则进入进餐状态。

**进餐状态:**进餐状态哲学家两边邻居则无法进餐。结束后需要放下筷子,将自身转为思考状态。同时为保证并行度,同时帮助两边邻居检查其状态,若邻居可以进餐,则帮他们解锁

package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	thinking = 0
	hungry   = 1
	eating   = 2
	philoCnt = 5
	mutex = sync.Mutex{}
	state []int
	philoMutex []sync.Mutex
)

func thinkOrEat() {
	time.Sleep(time.Second)
}

func leftPos(i int) int {
	return (philoCnt + i - 1) % philoCnt
}

func rightPos(i int) int {
	return (i + 1) % philoCnt
}

func test(i int) {
	if state[i] == hungry && state[leftPos(i)] != eating && state[rightPos(i)] != eating {
		state[i] = eating
		philoMutex[i].Unlock()
	}
}

func getForks(i int) {
	mutex.Lock()
	state[i] = hungry
	test(i)
	mutex.Unlock()
	philoMutex[i].Lock()
}

func putForks(i int) {
	mutex.Lock()
	state[i] = thinking
	test(leftPos(i)) // 检查左右的哲学家是否可以进餐,以保证整体获得最大的并行度
	test(rightPos(i))
	mutex.Unlock()
}

func philosopher(i int) {
	for {
		thinkOrEat() // thinking
		getForks(i)  // hungry
		thinkOrEat() // eating
		putForks(i)
	}
}

func print() {
	for {
		mutex.Lock()
		fmt.Println(state)
		mutex.Unlock()
		time.Sleep(100 * time.Millisecond)
	}
}

func main() {
	state = make([]int, philoCnt)
	philoMutex = make([]sync.Mutex, philoCnt)

	for i := range philoMutex {
		philoMutex[i].Lock() // 先全部上锁
	}
	// i个哲学家开始就餐
	for i := 0; i < philoCnt; i++ {
		go philosopher(i)
	}
	// 监视进程
	go print()
	for {
		thinkOrEat()
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值