Go并发之sync.Cond

创建一个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()
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值