skynet学习笔记 源码之sknyet_monitor监视器

前言

sknyet_monitor的作用是监视work线程对消息的处理有没有疑似出现死循环。当出现这种情况时,会把目标context endless字段置为true,lua层通过skynet.lenless()判断当前处理是否出现死循环。

monitor结构

struct skynet_monitor {

    ATOM_INT version;  //原子累加的版本号

    int check_version;    //检查版本号

    uint32_t source;      //消息来源

    uint32_t destination; //目标

};

API

struct skynet_monitor * skynet_monitor_new();                                                                        //新建

void skynet_monitor_delete(struct skynet_monitor *);                                                              //删除

void skynet_monitor_trigger(struct skynet_monitor *, uint32_t source, uint32_t destination); //赋值来源目标

void skynet_monitor_check(struct skynet_monitor *);                                                              //检查函数

主循环

每5秒对所以worker线程进行一次检查调用。

static void *

thread_monitor(void *p) {

    struct monitor * m = p;

    int i;

    int n = m->count;

    skynet_initthread(THREAD_MONITOR);

    for (;;) {

        CHECK_ABORT

        for (i=0;i<n;i++) {

            skynet_monitor_check(m->m[i]);

        }

        for (i=0;i<5;i++) { 

            CHECK_ABORT

            sleep(1);

        }

    }

 

    return NULL;

}

设置from to

调用消息处理回调时,先设置好检查的来源handle和目标handle,消息处理完了清除来源和目标信息。

过程中version会累计2次。

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);

}

check函数

当检查到超时处理超时,会把字段endless赋值为0,然后打印一个日志。

void 

skynet_context_endless(uint32_t handle) {

    struct skynet_context * ctx = skynet_handle_grab(handle);

    if (ctx == NULL) {

        return;

    }

    ctx->endless = true;

    skynet_context_release(ctx);

}

 

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;

    }

}

lua sknyet.endless处理流程

skynet.endless返回true时,context数据endless字段会赋值为false

那么问题来了:如果第一次消息处理时间超时,endless已经置为true了,第二消息处理时我们调用sknyet.endless的返回值是啥呢?

--skynet.lua

function skynet.endless()

    return (c.intcommand("STAT", "endless") == 1)

end

--lua-skynet.c

static int

lintcommand(lua_State *L) {

...

result = skynet_command(context, cmd, parm);

...

}

--skynet_server.c

static const char *

cmd_stat(struct skynet_context * context, const char * param) {

....

    } else if (strcmp(param, "endless") == 0) {

        if (context->endless) {

            strcpy(context->result, "1");

            context->endless = false;

        } else {

            strcpy(context->result, "0");

        }

    } 

...

    return context->result;

}

问题测试

local skynet = require "skynet"

 

local function test_func()

    print(skynet.endless())

end

 

skynet.start(function ()

    skynet.error("test_service begin")

    local cur_time = os.time()

    while true do

        local now_time = os.time()

        if now_time - cur_time > 10 then

            skynet.timeout(100,test_func)

            break

        end

    end

    skynet.error("test_service end")

end)

测试结果为true

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值