打印零与奇偶数(leetcode 1116)
方法1:使用互斥锁和条件变量
package mainimport ("fmt""sync"
)type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int
}func NewZeroEvenOdd(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()}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}
方法2:使用通道同步
package mainimport ("fmt""sync"
)type ZeroEvenOdd struct {n intzeroCh chan struct{}evenCh chan struct{}oddCh chan struct{}done chan struct{}
}func NewZeroEvenOdd(n int) *ZeroEvenOdd {z := &ZeroEvenOdd{n: n,zeroCh: make(chan struct{}),evenCh: make(chan struct{}),oddCh: make(chan struct{}),done: make(chan struct{}),}close(z.zeroCh) return z
}func (z *ZeroEvenOdd) Zero(printNumber func(int)) {for i := 0; i < z.n; i++ {<-z.zeroChprintNumber(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.evenChprintNumber(i)z.zeroCh <- struct{}{}}
}func (z *ZeroEvenOdd) Odd(printNumber func(int)) {for i := 1; i <= z.n; i += 2 {<-z.oddChprintNumber(i)z.zeroCh <- struct{}{}}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}
方法3:使用原子计数器
package mainimport ("fmt""sync""sync/atomic"
)type ZeroEvenOdd struct {n intcurrent int32cond *sync.Cond
}func NewZeroEvenOdd(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()}
}func main() {n := 5zeo := NewZeroEvenOdd(n)var wg sync.WaitGroupwg.Add(3)printFunc := func(x int) {fmt.Print(x)}go func() {defer wg.Done()zeo.Zero(printFunc)}()go func() {defer wg.Done()zeo.Even(printFunc)}()go func() {defer wg.Done()zeo.Odd(printFunc)}()wg.Wait()fmt.Println()
}
哲学家进食
package mainimport ("fmt""sync""time"
)const numPhilosophers = 5type Philosopher struct {id intleftFork *sync.MutexrightFork *sync.MutexeatingTimes 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.rightForkif p.id%2 == 0 { 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 chan struct{}, wg *sync.WaitGroup) {defer wg.Done()for i := 0; i < 3; i++ { p.think()sem <- struct{}{}p.eat()<-sem}
}func main() {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],}}sem := make(chan struct{}, numPhilosophers-1)var wg sync.WaitGroupfor _, 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)}
}