创建一个sync.Cond变量时首先要将其与一个sync.Locker接口进行绑定:
var mu sync.Mutex
var cond sync.Cond=sync.NewCond(&mu)
之后,
cond.Wait()
就等价于是
(1) mu.Unlock(), 给出此锁,此goroutine被挂起…
(2)一直等待,知道某个goroutine做出调用: cond.Broadcast()
(3)此进程被唤醒,执行mu.Lock(), 重新申请锁
(4)申请到锁之后,继续执行cond.Wait()语句后面的语句
guests上厕所,manager加厕纸的问题
package main
import (
"fmt"
"sync"
"time"
)
var (
wg sync.WaitGroup
papers int = 5
lock sync.Mutex
cond = sync.NewCond(&lock)
done = false
)
var guest = func(id int) {
// join the queue
lock.Lock()
defer lock.Unlock()
// get into the toilet
fmt.Printf("guest ID: %d is entering the toilet\n", id)
for papers < 1 {
// check if toilet papers are available
fmt.Printf("Not enough toilet paper in the toilet, guest ID: %d is leaving...\n", id)
cond.Wait() // steps of this call: (1) lock.Unlock() (2) suspend the goroutine (3) call lock.Lock() when receiving a signal
// reacquire the lock .....
fmt.Printf("Guest ID: %d enters the toilet again\n", id)
}
fmt.Printf("Guest ID: %d is giving a shit....\n", id)
papers -= 1
time.Sleep(time.Second)
fmt.Printf("Guest ID: %d is finished, remaining papers: %d \n", id, papers)
if papers < 1 {
// notify the manager if there is not enough toilet papers
cond.Broadcast()
fmt.Printf("Guest ID: %d notifies the manager that the toilet papers is not enough\n", id)
}
}
var manager = func() {
//join the queue
lock.Lock()
defer lock.Unlock()
fmt.Println("the manager has entered the toilet to check the availability of the papers...")
for papers > 0 && !done {
fmt.Println("toilet papers are still enough, the manager is leaving...")
cond.Wait() // lock.Unlock(), then suspend until a guest sends a signal and reacquire the lock
}
fmt.Println("the manager is supplying more papers...")
papers += 5
fmt.Printf("remaining papers: %d \n", papers)
cond.Broadcast() // telling guests that papers has been supplemented
}
func main() {
guestsNum, rounds := []int{1, 2, 3, 4, 5}, 2
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < rounds; i++ {
for _, guestNum := range guestsNum {
guest(guestNum)
time.Sleep(time.Second)
}
}
cond.Broadcast()
done = true
}()
go func() {
defer wg.Done()
for !done {
manager()
}
}()
wg.Wait()
}
enqueuer往队列加元素,dequeuer从队列删除元素的问题
package main
import (
"fmt"
"sync"
)
var (
queue = make([]int, 0, 10)
lock sync.Mutex
cond = sync.NewCond(&lock)
queueLength = 3
wg sync.WaitGroup
c = make(chan interface{})
)
func showQueue() {
for i := 0; i < len(queue); i++ {
fmt.Printf("%d", queue[i])
if i == len(queue)-1 {
fmt.Printf("\n")
} else {
fmt.Printf(" ")
}
}
}
func enqueue(id, num int, c chan interface{}) {
<-c
defer wg.Done()
lock.Lock()
defer lock.Unlock()
for len(queue) == queueLength {
cond.Wait()
}
queue = append(queue, num)
cond.Signal()
fmt.Printf("-----> enqueuer #%d adds %d to the queue: ", id, num)
if len(queue) > 0 {
showQueue()
} else {
fmt.Println("EMPTY")
}
}
func dequeue(id int, c chan interface{}) {
<-c
defer wg.Done()
lock.Lock()
defer lock.Unlock()
for len(queue) == 0 {
cond.Wait()
}
// get the head element of the queue
num := queue[0]
queue = queue[1:]
cond.Signal()
fmt.Printf("<----- dequeuer #%d removes %d from the queue: ", id, num)
if len(queue) > 0 {
showQueue()
} else {
fmt.Println("EMPTY")
}
}
func main() {
nums := []int{20, 21, 31, 41, 4, 5, 23, 4, 5, 6}
wg.Add(2 * len(nums))
for id, num := range nums {
go enqueue(id, num, c)
go dequeue(id, c)
}
close(c)
wg.Wait()
}