原 4.5-3 并发技术8:条件变量案例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010986776/article/details/86308874

案例1:服务器负载控制

  • 监听最大客户端连接数
  • 服务端协程:只要服务器过载,就通知控制协程,并进入阻塞等待
  • 控制协程:受到服务端预警,削减客户端数量,并通知服务端(预警已解除)
package main

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

/*
服务器负载控制
·监听最大客户端连接数
·服务端协程:只要服务器过载,就通知控制协程,并进入阻塞等待
·控制协程:受到服务端预警,削减客户端数量,并通知服务端(预警已解除)
*/
type Server struct {
	maxConnections int
	connections    int
	chAlarm        chan bool
	cond           *sync.Cond
}

/*服务端工厂方法*/
func NewServer(maxConnections int) *Server {
	server := new(Server)

	//初始化最大连接数
	server.maxConnections = maxConnections

	//初始化条件变量
	server.cond = sync.NewCond(&sync.Mutex{})

	//初始化预警管道
	server.chAlarm = make(chan bool,0)

	return server
}

/*启动过载处理器*/
func (s *Server) StartOverloadHandler() {
	fmt.Println("StartOverloadHandler...")

	go func() {
		for {
			//阻塞接收预警消息
			<-s.chAlarm
			fmt.Println("已收到负载预警")

			//加锁削减客户端数量,并发送预警解除广播
			s.cond.L.Lock()
			<-time.After(3 * time.Second)
			s.connections -= rand.Intn(s.maxConnections)
			fmt.Println("s.connections=", s.connections)

			//发送预警解除通知(会通知到Wait中的服务端主程序)
			s.cond.Signal()

			fmt.Println("过载预警已解除")
			s.cond.L.Unlock()
		}
	}()
}

func (s *Server) Run() {
	for {
		//加锁检测是否过载
		s.cond.L.Lock()

		/*只要过载,就发送预警,并释放资源锁并阻塞等待*/
		for s.connections >= s.maxConnections {
			//发送预警
			s.chAlarm <- true
			fmt.Println("过载预警已发送")

			//阻塞等待预警解除
			s.cond.Wait()
		}

		//接入客户端
		time.Sleep(1 * time.Second)
		s.connections ++
		fmt.Println("已接入客户端:s.connections=", s.connections)
		s.cond.L.Unlock()
	}
}

func main() {
	server := NewServer(5)

	//服务端跑起负载处理器
	server.StartOverloadHandler()

	//运行服务器主程序
	server.Run()
}

案例2:城管来了

  • 多个烧烤摊主协程监听城管大队的动向
  • 只要出动就发消息通知工会主席,并进入阻塞等待至被唤醒,否则就提供露天烧烤
  • 工会主席协程:收到烧烤摊主们的消息后,出面摆平城管大队,并广播通知所有烧烤摊主恢复营业
  • 这里的广播我们使用了一对多的广播:cond.Broadcast()

代码实现

package main

import (
	"fmt"
	"sync"
	"time"
)

/*
城管预警
·监听城管大队
·烧烤摊集群:
	监听城管大队,
	只要出动就发消息通知工会主席并进入阻塞等待至被唤醒
	否则就提供露天烧烤
·工会主席:摆平城管大队,并广播通所有烧烤摊主
*/

func main() {
	var dangerous = false
	cond := sync.NewCond(&sync.Mutex{})
	chDanger := make(chan string, 1)

	for i := 1; i <= 3; i++ {
		go func(index int) {
			for {
				//只要城管出来,就等待起来
				cond.L.Lock()
				for dangerous == true {
					//发送预警()
					select {
					case chDanger <- "城管来了!!!":
						fmt.Println(index,"城管来了!!!")
						fmt.Println(index, ":进入蛰伏状态")
					default: //已经有人发过了
					}

					fmt.Println(index, ":进入蛰伏状态")
					cond.Wait()
				}
				cond.L.Unlock()

				//城管没有出来
				fmt.Println(index, ":提供露天烧烤...")
				time.Sleep(3 * time.Second)
			}
		}(i)
	}

	go func() {
		for {

			select {

			case <-chDanger:
				//帮大家平事
				cond.L.Lock()
				time.Sleep(3 * time.Second)
				dangerous = false
				cond.Broadcast()//唤醒所有人
				fmt.Println("事情已经摆平")
				cond.L.Unlock()

			default:
				//日常生活
				fmt.Println("工会主席的日常幸福生活...")
				dangerous = true
				time.Sleep(7 * time.Second)
			}

		}
	}()

	time.Sleep(365 * time.Second)
}

猜你喜欢

转载自blog.csdn.net/u010986776/article/details/86308874