• skynet源码分析之skynet_handle


    skynet_handle是所有服务(ctx)的仓库(handle_storage),存储所有ctx。

    struct handle_name { //ctx的handle与name对应关系
            char * name;
            uint32_t handle;
    };
    
    struct handle_storage { //管理所有ctx结构
            struct rwlock lock; //读写锁
    
            uint32_t harbor; //每个skynet节点可配置一个唯一harbor,用于与其他节点组网
            uint32_t handle_index; //下次从handle_index位置开始查找空的位置
            int slot_size; //已分配的ctx的容量
            struct skynet_context ** slot; //slot_size容量的数组,每一项指向一个ctx
            
            int name_cap; //已分配ctx名字的容量
            int name_count; //已用的名字
            struct handle_name *name; //name_cap容量的数组,每一项是一个handle_name
    };
    
    static struct handle_storage *H = NULL;

    skynet启动时初始化handle_storage(S)

    void skynet_handle_init(int harbor) { //初始化,harbor在配置文件中可配置
            assert(H==NULL);
            struct handle_storage * s = skynet_malloc(sizeof(*H));
            s->slot_size = DEFAULT_SLOT_SIZE;
        //给slot分配slot_size个ctx内存,
            s->slot = skynet_malloc(s->slot_size * sizeof(struct skynet_context *));
            memset(s->slot, 0, s->slot_size * sizeof(struct skynet_context *));
    
            rwlock_init(&s->lock); //读写锁
            // reserve 0 for system
        // harbor取高8位,所以最多可组网2^8=255 skynet节点
            s->harbor = (uint32_t) (harbor & 0xff) << HANDLE_REMOTE_SHIFT;
            s->handle_index = 1;
            s->name_cap = 2;
            s->name_count = 0;
        //给name分配name_cap个handle_name内存
    
            s->name = skynet_malloc(s->name_cap * sizeof(struct handle_name));
    
            H = s;
    
            // Don't need to free H
    }

    为了效率,S->lock采用读写锁,因为获取一个ctx(读)的频率要远远大于创建/杀掉(写)一个ctx的频率,所以工作线程可以并发获取ctx。

    S->harbor在skynet启动文件中配置,每个skynet节点可配置唯一的harbor,用于与其他skynet节点组网,harbor占8位,所以最高可组网2^8个。

    S->slot存放所有ctx指针,是一个数组,容量为S->slot_size。当new一个ctx时,会给ctx注册一个对应的唯一的handle(skynet_handle_register)。handle从S->handle_index开始循环,通过handle&(S->slot_size-1)映射成一个hash值,如果在slot中未使用,则找到ctx对应的handle,在slot存放ctx指针,并设置ctx->handle=hande。当找不到空位置(数组满)时,重新申请之前2倍容量大小的内存空间,然后把数据迁移到新的空间里。这不就是c++里vector的实现方式嘛,skynet里有很多类似的实现机制,用数组+容量实现类似vector的功能。当kill一个ctx时会回收handle(skynet_handle_retire),置空ctx在slot里位置,供下一个ctx使用。skynet里每个ctx都有一个唯一的handle对应,向某个ctx发送消息时,都是通过handle找到对应的ctx,然后向ctx的消息队列里push消息。注:handle是uint32_t,其中高8位为harbor id,低24位为handle id,所以总共可创建2^24个ctx。

    在上层逻辑很难记住每个handle具体代表哪个服务,通常会为handle注册name(不限一个),通过name找到对应的handle,通过S->name实现。S->name是一个数组,类似S->slot,动态分配内存,S->name_cap表示数组容量。S->name是按handle_name->name升序排序的,通过二分查找快速地查找name对应的handle(skynet_handle_findname)。给handle注册name时,也需保证注册完S->name有序(skynet_handle_namehandle)

  • 相关阅读:
    Shiro笔记(三)shiroFilter拦截器配置原则
    Shiro笔记(二)Shiro集成SpringMVC的环境配置
    Shiro笔记(一)Shiro整体介绍
    javaNIO的总结
    Redis的工作流程
    Nginx的配置安装和使用
    Linux下java开发环境配置总结
    php 基础知识 post 和get 两种传输方式的区别
    php 高级 多台web服务器共享session的方法
    php 基础知识 SESSION 和 COOKIE 的区别
  • 原文地址:https://www.cnblogs.com/RainRill/p/8260466.html
Copyright © 2020-2023  润新知