大部分系统都存在守护进程,进行整个程序的监控

Go中也存在类似的监控G

  • 永不终止的循环
  • 轮询网络
  • 抢占长期占用M的G
  • GC

监控

在GMP那一章我们提到过在程序一开始的时候,Go会启动一个主G

等待资源与等待锁并不是同一回事

  • 然后由它来创建新的M
  • 会根据所在的系统clone出新的线程
  • 由该线程调用sysmon启动系统监控

sysmon线程就是Go中进行系统监控的线程

  • 先会检查是否存在死锁
    • 计算当前线程数
      • 通过程序线程相关的数据计算获取
        • 0,有活跃线程,无死锁
        • <0,程序状态不一致导致的计算不准确
        • =0,进一步检查状态
          • 有G可以运行(或者正在运行),但是实际上没有线程在跑,说明都在空转,死锁
          • 存在休眠状态中的G,且存在等待的计时器(IO资源),否则报错且退出
          • 全部G都处于不会再运行的状态时,说明主程序准备退出了
    • 是否存在running状态的G
    • 处理器上是否存在计时器
  • 进入监控循环
    • 每次循环都会调用usleep挂起线程
    • 运行计时器,获取下一个需要触发的计时器
      • 即计算下一次sysmon线程被唤醒的时间
    • 轮询网络,处理过期文件描述符
      • 非阻塞调用netpoll,获取发生变动的文件描述符,并且把对应的G放入全局队列
      • 如果有空闲的M,调用startm启动线程执行
    • 抢占运行时间过久的G
      • 调用runtime.retake
        • 遍历全局的P
        • 当前P状态为运行中或者系统调用,且运行时间超过10ms,抢占P
        • 在系统调用中的P,如果有其他的G处于队列,抢占P
    • GC
      • 调用gcTrigger.test判断是否要触发回收
      • 需要的话GC使用的G同样需要进入队列