go的sync包学习-sync.RWMutex

时间:2025-02-07 07:06:11
package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

type Cinema struct {
	rw *sync.RWMutex
}

type Person struct {
	Name string
}

type Admin struct {
	Name string
}

func main() {
	//example01()
	exmples2()
}

func (p *Person) SitDown(wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("%s 观众坐下!\n", p.Name)
}

func (p *Person) StartWatch() {
	fmt.Printf("%s 开始观看!\n", p.Name)
	i := time.Duration(rand.Intn(5) + 1)
	time.Sleep(i * time.Second)
	fmt.Printf("%s 观看结束!\n", p.Name)
}

func (p *Person) WatchMovie(c *Cinema, wg *sync.WaitGroup, b chan int) {
	c.rw.RLock()
	//先坐下
	p.SitDown(wg)
	<-b
	//看电影
	p.StartWatch()
	c.rw.RUnlock()
}

func (a *Admin) ChangeMovie(c *Cinema, wg *sync.WaitGroup) {
	defer wg.Done()
	c.rw.Lock()
	fmt.Printf("所有观众看完电影,%s管理员切换影片\n", a.Name)
	c.rw.Unlock()
}
func example01() {
	c := &Cinema{rw: &sync.RWMutex{}}
	a := &Admin{Name: "超人"}
	b := make(chan int)
	wg := sync.WaitGroup{}
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func(i int, c *Cinema, wg *sync.WaitGroup, b chan int) {
			p := Person{
				Name: fmt.Sprintf("%d 号观众", i),
			}
			p.WatchMovie(c, wg, b)
		}(i, c, &wg, b)
	}
	wg.Wait()
	fmt.Printf("所有观众入座,开始播放电影\n")
	close(b)
	wg.Add(1)
	go func(wg *sync.WaitGroup) {
		a.ChangeMovie(c, wg)
	}(&wg)
	wg.Wait()
}

type Desk struct {
	rw     *sync.RWMutex
	Snacks int
}

func (d *Desk) PlaceSnacks(wg *sync.WaitGroup) {
	defer wg.Done()
	d.rw.Lock()
	d.Snacks = 10
	time.Sleep(3 * time.Second)
	fmt.Printf("零食准备完毕...\n")
	d.rw.Unlock()
}
func (p *Person) GetSnacks(d *Desk, wg *sync.WaitGroup) {
	for !d.rw.TryRLock() {
		fmt.Printf("桌上没零食,%s 望眼欲穿\n", p.Name)
		time.Sleep(2 * time.Second)
	}
	d.rw.RUnlock()

	defer wg.Done()
	defer d.rw.Unlock()
	d.rw.Lock()
	if d.Snacks > 0 {
		fmt.Printf("%s 抢到零食,开心\n", p.Name)
		d.Snacks--
		return
	}
	fmt.Printf("%s 没抢到零食,难受\n", p.Name)
}
func exmples2() {

	d := Desk{
		rw: &sync.RWMutex{},
	}
	wg := sync.WaitGroup{}
	wg.Add(12)
	go d.PlaceSnacks(&wg)
	for i := 0; i < 11; i++ {
		p := Person{
			Name: fmt.Sprintf("%d 号猿猴", i),
		}
		go p.GetSnacks(&d, &wg)
	}
	wg.Wait()
}