作业题如下:

假设存在一个生产者,依次产生数字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();
}

 

结果如下: