范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

skynet源码阅读系列04skynetstart收尾

  上一小节主要是梳理了一下  skynet_context_new()   的功能。
  skynet_context_new()   主要功能是创建一个 skynet_context  。
  根据传入的name 从 配置的 cpath 路径对应的  *.so   库中查找。
  我们写的 C 服务需要包含四个函数, 假如 name 为  logger  , 则这四个函数的函数名分别为logger_create logger_release logger_init logger_signal
  skynet_context   结构体包含以下成员:struct skynet_context {     void * instance;                // 创建出的服务实例     struct skynet_module * mod;     // 内存里该C服务句柄     void * cb_ud;                        skynet_cb cb;     struct message_queue *queue;    // 该服务的消息队列     ATOM_POINTER logfile;     uint64_t cpu_cost;  // in microsec     uint64_t cpu_start; // in microsec     char result[32];                // 暂存结果     uint32_t handle;                // 启动该服务后,服务号     int session_id;     ATOM_INT ref;     int message_count;                  bool init;                      // init 之后为false     bool endless;                        bool profile;                   // 配置文件 profile 的值      CHECKCALLING_DECL };
  上述成员变量没注释的从main看到这里,暂时不清楚是做什么的,往后继续阅读就清楚了。
  今天我们接着  skynet_start()   继续看, 完整的函数体在下面。void  skynet_start(struct skynet_config * config) {     // register SIGHUP for log file reopen     struct sigaction sa;     sa.sa_handler = &handle_hup;     sa.sa_flags = SA_RESTART;     sigfillset(&sa.sa_mask);     sigaction(SIGHUP, &sa, NULL);      if (config->daemon) {         if (daemon_init(config->daemon)) {             exit(1);         }     }     skynet_harbor_init(config->harbor);     skynet_handle_init(config->harbor);     skynet_mq_init();     skynet_module_init(config->module_path);     skynet_timer_init();     skynet_socket_init();     skynet_profile_enable(config->profile);      struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);     if (ctx == NULL) {         fprintf(stderr, "Can"t launch %s service ", config->logservice);         exit(1);     }      skynet_handle_namehandle(skynet_context_handle(ctx), "logger");      bootstrap(ctx, config->bootstrap);      start(config->thread);      // harbor_exit may call socket send, so it should exit before socket_free     skynet_harbor_exit();     skynet_socket_free();     if (config->daemon) {         daemon_exit(config->daemon);     } }
  只剩下下面这点没看了。 skynet_start(struct skynet_config * config) {     // ...     skynet_handle_namehandle(skynet_context_handle(ctx), "logger");      bootstrap(ctx, config->bootstrap);      start(config->thread);      // harbor_exit may call socket send, so it should exit before socket_free     skynet_harbor_exit();     skynet_socket_free();     if (config->daemon) {         daemon_exit(config->daemon);     } }
  skynet_handle_namehandle(skynet_context_handle(ctx), "logger"); const char *  skynet_handle_namehandle(uint32_t handle, const char *name) {     rwlock_wlock(&H->lock);      const char * ret = _insert_name(H, name, handle);      rwlock_wunlock(&H->lock);      return ret; }
  我们可以看到, skynet_handle_namehandle()   的功能是 _insert_name()  。
  看看  _insert_name()   的具体实现:static const char * _insert_name(struct handle_storage *s, const char * name, uint32_t handle) {     int begin = 0;     int end = s->name_count - 1;     while (begin<=end) {         int mid = (begin+end)/2;         struct handle_name *n = &s->name[mid];         int c = strcmp(n->name, name);         if (c==0) {             return NULL;         }         if (c<0) {             begin = mid + 1;         } else {             end = mid - 1;         }     }     char * result = skynet_strdup(name);      _insert_name_before(s, result, handle, begin);      return result; }
  很明显的一个二分查找,判断传入的 name 是否在  H->name  里, 这是一个指针,指向一块内存,其内存元素的类型为 skynet_name  , 定义如下:struct handle_name {     char * name;     uint32_t handle; };  struct handle_storage {     //...     int name_cap;       // *name 指向内存块的容量     int name_count;     // *name 指向内存块当前已经占用了几个元素,每个元素为一个 skynet_name     struct handle_name *name;   // 指向一块内存 };
  为什么这里可以使用二分查找?
  我们看下  strcmp()   函数的功能
  百度百科:strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1str2,则返回正数。
  我们可以依据返回的结果判断,如果为0说明找到了,直接返回,后面的逻辑就不跑了,如果 <0  ,说明结果在mid的右边,begin = mid + 1  , 反之 end = mid - 1  。
  既然可以使用了二分查找,那一定要保证数组的有序咯?
  我们接着往下看,
  char * result = skynet_strdup(name);   将 name 拷贝了一份, 为什么要拷贝,下面解释。
  _insert_name_before(s, result, handle, begin);   函数原型如下:static void _insert_name_before(struct handle_storage *s, char *name, uint32_t handle, int before) {     if (s->name_count >= s->name_cap) {         s->name_cap *= 2;         assert(s->name_cap <= MAX_SLOT_SIZE);         struct handle_name * n = skynet_malloc(s->name_cap * sizeof(struct handle_name));         int i;         for (i=0;iname[i];         }         for (i=before;iname_count;i++) {             n[i+1] = s->name[i];         }         skynet_free(s->name);         s->name = n;     } else {         int i;         for (i=s->name_count;i>before;i--) {             s->name[i] = s->name[i-1];         }     }     s->name[before].name = name;     s->name[before].handle = handle;     s->name_count ++; }
  首先我们看  else   分支,此时 H->name   指向的内存还没放满元素,将从 before 下标开始到之后一个元素,将数组统一向后挪一个位置,不过都是从末端开始,到before 截至。
  before 也就是传入函数的begin, 是 name 将要插入的位置,将下标比begin 大的元素往后移,将 name 插入begin的位置,从而保证了数组的有序。
  如果  if (s->name_count >= s->name_cap)   如果容量不够了,将容量扩充至原来的两倍,并且有一个 MAX_SLOT_SIZE  最大值内存上限,将 before 之前的元素重新写入内存,之后的元素向后挪一个位置,同时释放掉原内存空间,中间 before 的位置写入 name。
  注意这里的释放操作,也就是为什么  _insert_name()  里为什么要拷贝一份的原因了。
  接下来是  bootstrap(ctx, config->bootstrap); static void bootstrap(struct skynet_context * logger, const char * cmdline) {     int sz = strlen(cmdline);     char name[sz+1];     char args[sz+1];     int arg_pos;     sscanf(cmdline, "%s", name);     arg_pos = strlen(name);     if (arg_pos < sz) {         while(cmdline[arg_pos] == " ") {             arg_pos++;         }         strncpy(args, cmdline + arg_pos, sz);     } else {         args[0] = "";     }     struct skynet_context *ctx = skynet_context_new(name, args);     if (ctx == NULL) {         skynet_error(NULL, "Bootstrap error : %s ", cmdline);         skynet_context_dispatchall(logger);         exit(1);     } }
  我们拿  example/config   下的配置举例,config 下的 bootstrap 配置如下。bootstrap = "snlua bootstrap"   -- The service for bootstrap
  bootstrap()   函数体内在调用 skynet_context_new()   之前,主要是把 "snlua" 赋值给 name,而空格之后的字符串即为args的值。
  然后再把 name,args传入 skynet_context_new() 函数,从 snlua.so 中查找模块并创建实例。
  如果失败了,把消息队列里的消息分发完,退出。
  start(config->thread); static void start(int thread) {     pthread_t pid[thread+3];      struct monitor *m = skynet_malloc(sizeof(*m));     memset(m, 0, sizeof(*m));     m->count = thread;     m->sleep = 0;      m->m = skynet_malloc(thread * sizeof(struct skynet_monitor *));     int i;     for (i=0;im[i] = skynet_monitor_new();     }     if (pthread_mutex_init(&m->mutex, NULL)) {         fprintf(stderr, "Init mutex error");         exit(1);     }     if (pthread_cond_init(&m->cond, NULL)) {         fprintf(stderr, "Init cond error");         exit(1);     }      create_thread(&pid[0], thread_monitor, m);     create_thread(&pid[1], thread_timer, m);     create_thread(&pid[2], thread_socket, m);      static int weight[] = {          -1, -1, -1, -1, 0, 0, 0, 0,         1, 1, 1, 1, 1, 1, 1, 1,          2, 2, 2, 2, 2, 2, 2, 2,          3, 3, 3, 3, 3, 3, 3, 3, };     struct worker_parm wp[thread];     for (i=0;ithread + 3  。struct monitor {     int count;     struct skynet_monitor ** m;     pthread_cond_t cond;     pthread_mutex_t mutex;     int sleep;     int quit; };
  创建了一个 monitor 结构体, 初始化数据 count: config->thread sleep: 0 m: 为每个thread 创建了一个 skynet_monitor cond: 条件变量 mutex: 互斥锁 create_thread(&pid[0], thread_monitor, m); create_thread(&pid[1], thread_timer, m); create_thread(&pid[2], thread_socket, m);
  创建了三个线程,monitor, timer, socket, 这就是声明数组大小为 thread + 3 的原因。
  create_thread()   的函数原型如下:static void create_thread(pthread_t *thread, void *(*start_routine) (void *), void *arg) {     if (pthread_create(thread,NULL, start_routine, arg)) {         fprintf(stderr, "Create thread failed");         exit(1);     } }
  参数 thread: 指向线程的指针 start_routine: 指向函数的指针 arg: void 指针
  创建线程,并指明线程运行函数的起始地址,也就是我们传入的函数指针指向的地址,arg 将最为参数传递给 start_routine 函数。 static int weight[] = {          -1, -1, -1, -1, 0, 0, 0, 0,         1, 1, 1, 1, 1, 1, 1, 1,          2, 2, 2, 2, 2, 2, 2, 2,          3, 3, 3, 3, 3, 3, 3, 3, }; struct worker_parm wp[thread]; for (i=0;idaemon) {     daemon_exit(config->daemon); }
  最后join 调线程之后再把 harbor,socket,等相关资源释放掉。
  skynet_start()   到这里就结束了,是不是很奇怪,是不是感觉还有很多事情没有做(如果有skynet使用经验会有这种感觉),别急,后面我们继续看。

小米虽不自研系统,但MIUI,也在朝着鸿蒙的方向发展在去年6月份,华为的Harmony2。0系列发布之后,很多人就一直在问华为之外的友商,那就是大家用不用鸿蒙系统?当时荣耀做了表态,称现在安卓是首选,未来可能会考虑鸿蒙,其实就是婉拒小巧精致,音质出色,SoundPEATSAir3真无线蓝牙耳机体验很早以前接触过一款SoundPEATS泥炭的耳机,给V叔留下的最深印象是低音不错!现如今,市面上的无线耳机实在是太多了,想要找到一款性价比十足且音质给力的耳机,对于老司机们来说也不分布式学习之zookeeper3分布式学习之zookeeper3分布式很多地方都会用到zk,虽然这个技术出了很久,但是作为应用开发工程师可能这方面接触的还是比较少。我打算从浅入深的学习下zk的使用。Java操作z42iframe有哪些优缺点?(了解)iframe的优点1iframe能够原封不动地把嵌入的网页展现出来2如果有多个网页引用iframe,那么只需要修改iframe的内容,就可以实现调用每一个页面的更改,方便快捷3网页高飞芯片股还能不能碰?分析师这11支股还能涨半导体,即从智能手机到洗衣机的所有产品中都可以找到的微小芯片,是一项大生意。CNBC已让全球各地的分析师列出他们最看好的芯片股,因为该行业惊人的增长似乎将继续保持下去。香港海通国际于江雪我和哈苏的爱恨情仇哈苏X1DII50CXCD421哈苏X1DII50CXCD1。980哈苏这个品牌是我一直听说过,但是又一直不敢去碰的。在我脑海里,哈苏都是大师们用的机器,我这种路人,业余爱好者,感2025年宁夏市政车辆将全部由新能源车辆替代来源中国新闻网中新网银川1月5日电(记者杨迪)记者5日从宁夏生态环境厅获悉,近日,该部门印发宁夏回族自治区应对气候变化十四五规划(以下简称规划),规划中提到,到2025年,宁夏将实补贴退坡影响有限新能源车企斗法产品力来源中国证券报补贴退坡后我们还没接到厂家的提价通知,后续不排除有提价的可能。某4S店负责人王明(化名)告诉中国证券报记者。根据日前发布的2022年新能源汽车推广补贴方案,2022年融资丨赛岚医药完成近2亿元A轮融资,泽悦资本和鼎晖VGC联合领投创业邦获悉,专注于表观遗传学领域治疗技术和新药研发的赛岚医药(CytosinLabTherapeutics)宣布于近期完成近2亿元人民币的A轮融资。本轮融资由泽悦资本和鼎晖VGC联用了3个月华为Mate40pro和iPhone13pro后,憋了一肚子话想说很多朋友问快哥,华为的旗舰和苹果的旗舰怎么选,哪个更好用。因为这个问题其实涉及到每个人的使用方式和习惯,无法一概而论。所以快哥深度使用3个月的华为Mate40pro和iPhone1真正的奢侈品手机鼻祖vertu你用过吗说起比iPhone还贵的手机,除了8848你还知道什么品牌?高价手机并不是都能成为奢侈手机的,说起来奢侈手机,这个牌子还是8848的爸爸,8848手机身上多多少少都有它的影子。这个
iPhoneSE3售价沉船,贱卖苹果A15处理器仅售2529在iPhoneSE3首发时,苹果官方给出了标配机型3499的售价,迎来广大网友的不满,毕竟iPhoneSE3过时的外观设计很难获得更多的品牌溢价。并且发布会前,网络上多家媒体给出的编程语言流行指数Python稳居宝座,Java滑坡!作者h4cd本文经授权转载自开源中国(IDoschina2013)PYPL(PopularitYofProgrammingLanguage,编程语言流行指数)四月榜单已发布,目前包40家公司涉996工作制企业效益重要还是员工命重要?最近,996工作制一再引发社会关注。996工作制通常是指员工早9点上班晚9点下班,每周工作6天。日前有40多家互联网公司被指实行996工作制,其中也包括多家知名互联网公司。(据齐鲁Vue3,插槽,slot,单个slot,具名slot,作用域slot,案例代码插槽(slot)插槽,也就是slot,是组件的一块HTML模板,一个slot最核心的两个问题是显示不显示和怎样显示。插槽,子组件中的提供给父组件使用的一个占位符,用表示,父组件可以骑车十分钟,停车一小时,共享单车为何难还?世界上最远的距离不是生与死,而是我的车就停在白线内,APP却显示它没有回到P点文财经实习生韩馨雨记者李莹编辑余乐五一小长假过后,因部分地铁站封闭公交车停运,北京朝阳区街道上骑共享单教你如何在一部手机上同时登录两个微信号有时我们或许会由于某种原因,或者工作的需要,往往需要注册一个以上的微信号,然而许多人可能认为,一个手机只能登录一个微信号,这样就不是特别方便了。其实一部手机是可以同时登录两个微信号这2款老年代步车舒适又省电,续航240里7度电,能坐34人阅读本文前,请您先点击上面的关注,可以免费订阅我们的最新内容,感谢支持随着碳中和,碳达峰的提出,国家开始大力鼓励发展新能源。其中就包含了纯电动的老年代步车。现在很多四轮电动车跑不远苹果的引导模式,只是锁定这个应用,并不能锁定一张照片首先,我的ip要切换到3g然后再切换到4g,mi一样负2直接没得信号。其他品牌不知道,不过感觉也差不到哪里去。地下车库,我的SE是4G,信号3格。我的安卓4G变成3G,并且信号非常中金重申腾讯控股(00700。HK)中性评级目标价降12至451港元中金发布研究报告称,重申腾讯控股(00700。HK)中性评级,202223年收入及盈利预测不变,考虑到投资的公司估值有所倒退,目标价降12至451港元,另预计今年首季收入将同比持平50亿投资锂电铜箔,门外汉杭电股份如何破局?公司回应已组建一支优秀团队21世纪经济报道记者韩迅上海报道日前,杭电股份(603618。SH)发布公告称,公司拟以近期新设立的全资子公司江西杭电铜箔有限公司(下称江西杭电公司)为投资主体,在江西省南昌市小蓝宁夏130个科技创新团队在各领域大显身手中新网银川5月10日电(记者李佩珊)记者10日从宁夏科技厅获悉,截至2021年底,宁夏先后组建130个自治区级科技创新团队,予以近7000万元支持资金,累计对考核优秀的88个科技创