golang chan的用法

楚天乐 2214 1 条

实验目的

chan相关前置知识点,请参考本文底部链接。墙裂推荐阅读。

  1. 假设系统内除了主线程之外,有四个线程connector,sender,receiver,heartbeat
  • connector,负责建立网络连接,在连接断开的时候进行重连
  • sender,负责发送数据报
  • receiver,负责接收数据报
  • heartbeat,负责监控心跳
  1. 如何启动connector
  • connector需要等待ConnectorNotifier,值为1连接,值为2重连
  • 建立连接之后,发送三次ConnectorConnected,通知sender, sender,receiver可以开工
var ConnectorConnected chan int = make(chan int, 3)         // 已连接通知
func connector(){
    .....

    // 成功之后发送三次通告
    ConnectorConnectedNotifier <- 1
    ConnectorConnectedNotifier <- 1
    ConnectorConnectedNotifier <- 1
}
  1. 如何启动sender, receiver,以及heartbeat
  • 等待ConnectorConnectedNotifier,收到之后即可开始工作
  • 等待QuitNotifier进行退出
  • 分别发送SenderQuitedNotifier, ReceiverQuitedNotifier, HeartBeatQuitedNotifier告诉主线程自己已经退出
  1. 主线程如何工作
  • 发出ConnectorNotifier让connector建立连接
  • 启动connector,sender,receiver,beatheart
  • 等待键盘输入ctrl+c结束程序
  • 发送四次QuitNotifier,通告connector,sender,receiver,beatheart退出
  • 等待connector,sender,receiver,beatheart确认退出
  • 自己退出

下面这样写是不对的,因为没法保证时序(先收到ConnectorQuitedNotifier,在收到ReceiverQuitedNotifier)

<- ConnectorQuitedNotifier
<- ReceiverQuitedNotifier
<- SenderQuitedNotifier
<- HeartBeatQuitedNotifier

需要这样,乱序等待

// 等待线程退出:connector, sender, receiver, heartbeat
for i := 0; i < 4; {
    select{
    case <- ConnectorQuitedNotifier:
        i++
    case <- ReceiverQuitedNotifier:
        i++
    case <- SenderQuitedNotifier:
        i++
    case <- HeartBeatQuitedNotifier:
        i++
    }
}

代码实现

package main

import (
"fmt"
"os"
"os/signal"
"syscall"
)

var ConnectorNotifier chan int = make(chan int, 2)          // 连接器通知, 2个(1启动,2退出,3重连)
var ConnectorConnectedNotifier chan int = make(chan int, 3)         // 已连接通知
var ReceiverNotifier chan int = make(chan int)              // 接收器通知, (1启动,2退出)
var SenderNotifier chan int = make(chan int)                // 发送器通知,  (1启动,2退出)
var QuitNotifier chan int = make(chan int, 4)               // 退出通知, 4个
var FinishNotifier chan int = make(chan int)

var ConnectorQuitedNotifier chan int = make(chan int)       // 接收器通知, 1启动,2退出
var ReceiverQuitedNotifier chan int = make(chan int)        // 接收器通知, 1启动,2退出
var SenderQuitedNotifier chan int = make(chan int)          // 接收器通知, 1启动,2退出
var HeartBeatQuitedNotifier chan int = make(chan int)       // 接收器通知, 1启动,2退出

func main(){
    // 标记启动连接器
    ConnectorNotifier <- 1

    go Connector()
    go Receiver()
    go Sender()
    go HeartBeat()

    // 等待ctrl + c退出
    fmt.Println("等待退出")
    SetupCloseHandler()
    <- FinishNotifier
    fmt.Println("准备退出,开始清理")

    // 通知线程退出:connector, sender, receiver, heartbeat
    QuitNotifier <- 1
    QuitNotifier <- 1
    QuitNotifier <- 1
    QuitNotifier <- 1

    // 等待线程退出:connector, sender, receiver, heartbeat
    for i := 0; i < 4; {
        select{
        case <- ConnectorQuitedNotifier:
            i++
        case <- ReceiverQuitedNotifier:
            i++
        case <- SenderQuitedNotifier:
            i++
        case <- HeartBeatQuitedNotifier:
            i++
        }
    }

    fmt.Println("主程序退出")
}

/*监听ctrl+c控制主线程退出*/
func SetupCloseHandler() {
    c := make(chan os.Signal, 2)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    go func() {
        <-c
        FinishNotifier <- 1
        fmt.Println("\r- Ctrl+C pressed in Terminal")
    }()
}

/*
连接管理器
1. 首先试着建立连接,建立连接失败则报错,3秒后重试
2. 建立连接之后,通知其他线程连接已建立
3. 收到重连消息后,则进行重连
4. 收到退出消息后则退出
*/
func Connector(){
    var value int
    for {
        select{
        case value = <-ConnectorNotifier:
            if value == 1 || value == 2{
                // 连接
                fmt.Println("准备连接")

                fmt.Println("连接成功")

                ConnectorConnectedNotifier <- 1
                ConnectorConnectedNotifier <- 1
                ConnectorConnectedNotifier <- 1
            }
        case value = <-QuitNotifier:
            ConnectorQuitedNotifier <- 1
            fmt.Println("Connector退出")
        }
    }
}

func Receiver(){
    <- ConnectorConnectedNotifier
    fmt.Println("Receiver: 准备接收数据")

    fmt.Println("Receiver: 等待退出")
    <-QuitNotifier
    fmt.Println("Receiver: 退出")

    ReceiverQuitedNotifier <- 1
}

func Sender(){
    <- ConnectorConnectedNotifier
    fmt.Println("Sender: 准备发送数据")

    fmt.Println("Sender: 等待退出")
    <-QuitNotifier
    fmt.Println("Sender: 退出")

    SenderQuitedNotifier <- 1
}

func HeartBeat(){
    <- ConnectorConnectedNotifier
    fmt.Println("HeartBeat: 准备处理心跳")

    fmt.Println("HeartBeat: 等待退出")
    <-QuitNotifier
    fmt.Println("HeartBeat: 退出")

    HeartBeatQuitedNotifier <- 1
}

代码输出

等待退出
准备连接
连接成功
HeartBeat: 准备处理心跳
HeartBeat: 等待退出
Sender: 准备发送数据
Receiver: 准备接收数据
Receiver: 等待退出
Sender: 等待退出
- Ctrl+C pressed in Terminal
准备退出,开始清理
Sender: 退出
HeartBeat: 退出
Connector退出
Receiver: 退出
主程序退出

参考

https://studygolang.com/articles/17349

打赏

微信打赏

支付宝打赏



网友最新评论(1)

言简意赅,赞一个!

July 15th, 2021
发表我的评论
昵称 (必填)
邮箱 (必填)
网址
执行时间: 1710848165678.2 毫秒