打印零与奇偶数(leetcode 1116)
方法1:使用互斥锁和条件变量
package mainimport ( "fmt" "sync"
) type ZeroEvenOdd struct { n int zeroMutex 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 := 5 zeo := 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 int zeroCh 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 := 5 zeo := 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 int current int32 cond * 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 := 5 zeo := 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 = 5 type Philosopher struct { id int leftFork * 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) }
}