package main
import("fmt""sync")type ZeroEvenOdd struct{
n int
zeroMutex sync.Mutex
evenMutex sync.Mutex
oddMutex sync.Mutex
current int}funcNewZeroEvenOdd(n int)*ZeroEvenOdd {
z :=&ZeroEvenOdd{n: n}
z.evenMutex.Lock()
z.oddMutex.Lock()return z
}func(z *ZeroEvenOdd)Zero(printNumber func(int)){for i :=0; i < z.n; i++{
z.zeroMutex.Lock()printNumber(0)
z.current++if z.current%2==1{
z.oddMutex.Unlock()}else{
z.evenMutex.Unlock()}}}func(z *ZeroEvenOdd)Even(printNumber func(int)){for i :=2; i <= z.n; i +=2{
z.evenMutex.Lock()printNumber(i)
z.zeroMutex.Unlock()}}func(z *ZeroEvenOdd)Odd(printNumber func(int)){for i :=1; i <= z.n; i +=2{
z.oddMutex.Lock()printNumber(i)
z.zeroMutex.Unlock()}}funcmain(){
n :=5
zeo :=NewZeroEvenOdd(n)var wg sync.WaitGroup
wg.Add(3)
printFunc :=func(x int){
fmt.Print(x)}gofunc(){defer wg.Done()
zeo.Zero(printFunc)}()gofunc(){defer wg.Done()
zeo.Even(printFunc)}()gofunc(){defer wg.Done()
zeo.Odd(printFunc)}()
wg.Wait()
fmt.Println()}
方法2:使用通道同步
package main
import("fmt""sync")type ZeroEvenOdd struct{
n int
zeroCh chanstruct{}
evenCh chanstruct{}
oddCh chanstruct{}
done chanstruct{}}funcNewZeroEvenOdd(n int)*ZeroEvenOdd {
z :=&ZeroEvenOdd{
n: n,
zeroCh:make(chanstruct{}),
evenCh:make(chanstruct{}),
oddCh:make(chanstruct{}),
done:make(chanstruct{}),}close(z.zeroCh)// 初始允许zero执行return z
}func(z *ZeroEvenOdd)Zero(printNumber func(int)){for i :=0; i < z.n; i++{<-z.zeroCh
printNumber(0)if i%2==0{
z.oddCh <-struct{}{}}else{
z.evenCh <-struct{}{}}}close(z.done)}func(z *ZeroEvenOdd)Even(printNumber func(int)){for i :=2; i <= z.n; i +=2{<-z.evenCh
printNumber(i)
z.zeroCh <-struct{}{}}}func(z *ZeroEvenOdd)Odd(printNumber func(int)){for i :=1; i <= z.n; i +=2{<-z.oddCh
printNumber(i)
z.zeroCh <-struct{}{}}}funcmain(){
n :=5
zeo :=NewZeroEvenOdd(n)var wg sync.WaitGroup
wg.Add(3)
printFunc :=func(x int){
fmt.Print(x)}gofunc(){defer wg.Done()
zeo.Zero(printFunc)}()gofunc(){defer wg.Done()
zeo.Even(printFunc)}()gofunc(){defer wg.Done()
zeo.Odd(printFunc)}()
wg.Wait()
fmt.Println()}
方法3:使用原子计数器
package main
import("fmt""sync""sync/atomic")type ZeroEvenOdd struct{
n int
current int32
cond *sync.Cond
}funcNewZeroEvenOdd(n int)*ZeroEvenOdd {return&ZeroEvenOdd{
n: n,
current:0,
cond: sync.NewCond(&sync.Mutex{}),}}func(z *ZeroEvenOdd)Zero(printNumber func(int)){for i :=0; i < z.n; i++{
z.cond.L.Lock()for atomic.LoadInt32(&z.current)!=0{
z.cond.Wait()}printNumber(0)
atomic.StoreInt32(&z.current,int32(i+1))
z.cond.Broadcast()
z.cond.L.Unlock()}}func(z *ZeroEvenOdd)Even(printNumber func(int)){for i :=2; i <= z.n; i +=2{
z.cond.L.Lock()for atomic.LoadInt32(&z.current)!=int32(i){
z.cond.Wait()}printNumber(i)
atomic.StoreInt32(&z.current,0)
z.cond.Broadcast()
z.cond.L.Unlock()}}func(z *ZeroEvenOdd)Odd(printNumber func(int)){for i :=1; i <= z.n; i +=2{
z.cond.L.Lock()for atomic.LoadInt32(&z.current)!=int32(i){
z.cond.Wait()}printNumber(i)
atomic.StoreInt32(&z.current,0)
z.cond.Broadcast()
z.cond.L.Unlock()}}funcmain(){
n :=5
zeo :=NewZeroEvenOdd(n)var wg sync.WaitGroup
wg.Add(3)
printFunc :=func(x int){
fmt.Print(x)}gofunc(){defer wg.Done()
zeo.Zero(printFunc)}()gofunc(){defer wg.Done()
zeo.Even(printFunc)}()gofunc(){defer wg.Done()
zeo.Odd(printFunc)}()
wg.Wait()
fmt.Println()}
哲学家进食
package main
import("fmt""sync""time")const numPhilosophers =5type Philosopher struct{
id int
leftFork *sync.Mutex
rightFork *sync.Mutex
eatingTimes int}func(p *Philosopher)think(){
fmt.Printf("哲学家 %d 正在思考...\n", p.id)
time.Sleep(time.Second *1)}func(p *Philosopher)eat(){// 确定拿叉子的顺序(避免循环等待)
first, second := p.leftFork, p.rightFork
if p.id%2==0{// 偶数ID哲学家先拿右叉子
first, second = p.rightFork, p.leftFork
}// 获取叉子
first.Lock()
second.Lock()// 进餐
fmt.Printf("哲学家 %d 开始进餐 (第%d次)\n", p.id, p.eatingTimes+1)
time.Sleep(time.Second *1)
p.eatingTimes++// 释放叉子
second.Unlock()
first.Unlock()}func(p *Philosopher)dine(sem chanstruct{}, wg *sync.WaitGroup){defer wg.Done()for i :=0; i <3; i++{// 每个哲学家吃3次便于观察
p.think()// 获取就餐许可
sem <-struct{}{}
p.eat()<-sem
}}funcmain(){// 初始化叉子
forks :=make([]*sync.Mutex, numPhilosophers)for i :=range forks {
forks[i]=&sync.Mutex{}}// 创建哲学家
philosophers :=make([]*Philosopher, numPhilosophers)for i :=range philosophers {
philosophers[i]=&Philosopher{
id: i,
leftFork: forks[i],
rightFork: forks[(i+1)%numPhilosophers],}}// 使用信号量限制同时就餐人数(最多允许4人同时尝试拿叉子)
sem :=make(chanstruct{}, numPhilosophers-1)var wg sync.WaitGroup
// 开始就餐for_, p :=range philosophers {
wg.Add(1)go p.dine(sem,&wg)}
wg.Wait()// 统计每位哲学家就餐次数for_, p :=range philosophers {
fmt.Printf("哲学家 %d 总共进餐 %d 次\n", p.id, p.eatingTimes)}}