skynet 的 monitor 线程

struct skynet_monitor {
        ATOM_INT version;
        int check_version;
        uint32_t source;
        uint32_t destination;
};
  • skynet 的每个工作线程对应一个 skynet_monitor 结构体
  • version:当前的版本号
  • check_version:检查版本号
  • source:发送消息的 actor 地址
  • destination:接收消息的 actor 地址
void skynet_monitor_check(struct skynet_monitor *sm) {
    if (sm->version == sm->check_version) {
        if (sm->destination) {
            skynet_context_endless(sm->destination);
            skynet_error(NULL, "A message from [ :%08x ] to [ :%08x ] maybe in an endless loop (version = %d)", sm->source , sm->destination, sm->version);
        }
    } else {
        sm->check_version = sm->version;
    }
}
  • monitor 线程每 5s 执行 skynet_monitor_check 函数,如果发现 destination ,则表示该 actor 可能陷入死循环中,这里只把该 actor 标记为死循环状态
struct message_queue *skynet_context_message_dispatch(struct skynet_monitor *sm, struct message_queue *q, int weight) {
    ...
    skynet_monitor_trigger(sm, msg.source , handle);

     if (ctx->cb == NULL) {
        skynet_free(msg.data);
    } else {
        dispatch_message(ctx, &msg);
    }
    skynet_monitor_trigger(sm, 0,0);
    ...
}

skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) {
    sm->source = source;
    sm->destination = destination;
    ATOM_FINC(&sm->version);
}
  • 在调用 dispatch_message 处理 actor 的消息的前会调用 skynet_monitor_trigger 把该线程对应 skynet_monitor 的 destination 字段设置为目标 actor 的地址
  • 在调用 dispatch_message 处理 actor 的消息的后会调用 skynet_monitor_trigger 把该线程对应 skynet_monitor 的 destination 字段设置为无效
  • 每个线程都有一个 skynet_monitor 结构体用于记录监控信息
  • 工作线程执行消息处理前调用 skynet_monitor_trigger 把 skynet_monitor 的 destination 字段设置为处理函数所在 actor 的地址
  • 工作线程执行消息处理后调用 skynet_monitor_trigger 把 skynet_monitor 的 destination 字段设置为无效
  • monitor 线程每 5s 都会检查每个线程的 skynet_monitor 的 destination 字段是否有效,有效表示该 actor 对象的处理函数可能陷入死循环
  • monitor 线程检测到可能陷入死循环的 actor 只是把该 actor 标记为 endless 并打印错误