作业题如下:
假设存在一个生产者,依次产生数字0到9。存在一个奇数消费者,一个偶数消费者分别使用奇数和偶数,使用Go语言通道实现这个生产者消费者模型的代码如下:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func producer(odd chan<- int, even chan<- int) {
defer wg.Done()
for i := 0; i < 10; i++ {
if i%2 == 0 {
even <- i
} else {
odd <- i
}
}
close(odd)
close(even)
}
func oddConsumer(odd <-chan int) {
defer wg.Done()
for {
value, ok := <-odd
if !ok {
fmt.Println("Consumer odd, work done")
return
}
fmt.Printf("Consumer odd, get value %d\n", value)
}
}
func evenConsumer(even <-chan int) {
defer wg.Done()
for {
value, ok := <-even
if !ok {
fmt.Println("Consumer even, work done")
return
}
fmt.Printf("Consumer even, get value %d\n", value)
}
}
func main() {
oddChannel := make(chan int)
evenChannel := make(chan int)
wg.Add(3)
go producer(oddChannel, evenChannel)
go oddConsumer(oddChannel)
go evenConsumer(evenChannel)
wg.Wait()
}
这样实现出来的输出是无序的
更改程序使得数字按从小到大的顺序输出。
使用信号量方式解决,即sync中的条件变量。定义了两个条件变量oddPermit、evenPermit,分别用来在输出完时给对方发送信号,将输出的权力交给对方。因为最开始输出的是0,所以最开始将oddPermit上锁,阻塞oddConsumer()。输出偶数时,将evenPermit上锁,输出完时将oddPermit的锁打开,同理输出奇数时,将oddPermit上锁,输出完时将evenPermit的锁打开,这样就完成了奇数偶数的交替输出,在所有的数都输出完后,要将两个信号量解锁,避免之后一直阻塞。
代码如下:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var oddPermit sync.Cond
var evenPermit sync.Cond
func producer(odd chan<-int, even chan<-int){
defer wg.Done()
for i:=0;i<10;i++{
if i%2 == 0{
even<-i;
}else{
odd<-i;
}
}
close(odd)
close(even)
}
func oddConsumer(odd <-chan int){
defer wg.Done()
for{
oddPermit.L.Lock()
value, ok := <-odd
if !ok {
evenPermit.L.Unlock()
fmt.Printf("Consumer odd, work done\n")
return
}
fmt.Printf("Consumer odd, get value %d\n", value)
evenPermit.L.Unlock()
}
}
func evenConsumer(even <-chan int){
defer wg.Done()
for{
evenPermit.L.Lock()
value, ok := <-even
if !ok {
oddPermit.L.Unlock()
fmt.Printf("Consumer even, work done\n")
return
}
fmt.Printf("Consumer even, get value %d\n", value)
oddPermit.L.Unlock()
}
}
func main(){
oddChannel := make(chan int)
evenChannel := make(chan int)
oddPermit.L = new(sync.Mutex)
oddPermit.L.Lock();
evenPermit.L = new(sync.Mutex)
wg.Add(3)
go producer(oddChannel, evenChannel)
go oddConsumer(oddChannel)
go evenConsumer(evenChannel)
wg.Wait();
}
结果如下: