skynet 源码阅读 -- 启动主流程

Skynet 启动主流程分析

Skynet 是一个轻量级、高并发的服务器框架。它在启动时会进行一系列初始化操作,并启动多个不同功能的线程(Monitor、Timer、Worker、Socket),从而实现消息分发、定时器、网络I/O等核心功能。本文主要从 main() 函数开始一步步trace,循序渐进地看 Skynet 的启动过程以及各条线程的分工,为后续深入阅读 Skynet 源码做铺垫。


1. 启动入口 main 函数 -- skynet_main.c

int
main(int argc, char *argv[]) {// 1) 获取配置文件const char * config_file = NULL ;if (argc > 1) {config_file = argv[1];} else {fprintf(stderr, "Need a config file. usage: skynet configfilename\n");return 1;}// 2) Skynet全局初始化skynet_globalinit();skynet_env_init();sigign();  // 忽略部分信号struct skynet_config config;// 3) 解析配置文件struct lua_State *L = luaL_newstate();luaL_openlibs(L);// load_config 脚本读取 config_file 并将其返回到 Lua// ..._init_env(L);  // 将Lua中的配置项保存到C层lua_close(L);// 4) 将 Lua 解析到的配置写入 config 结构体config.thread =  optint("thread",8);config.module_path = optstring("cpath","./cservice/?.so");config.harbor = optint("harbor", 1);config.bootstrap = optstring("bootstrap","snlua bootstrap");config.daemon = optstring("daemon", NULL);config.logger = optstring("logger", NULL);config.logservice = optstring("logservice", "logger");config.profile = optboolean("profile", 1);// 5) 启动Skynetskynet_start(&config);// 6) 全局退出清理skynet_globalexit();return 0;
}

流程要点:

  1. 读取命令行参数:确定配置文件 config_file
  2. Skynet全局初始化skynet_globalinit / skynet_env_init 设置一些全局环境,注册信号处理等。
  3. 解析配置:通过 Lua 脚本来读取 config_file 并存到 struct skynet_config
  4. 调用 skynet_start:是 Skynet 的核心启动函数,后面会详细讲。
  5. 清理:退出时 skynet_globalexit 做一些释放资源操作(比如内存管理模块等)。

从这里可以看到:Lua 脚本用于配置 Skynet,通过 Lua 作为配置及引擎脚本。


2. skynet_start:初始化模块 & 启动多线程

void 
skynet_start(struct skynet_config * config) {// 1) 注册SIGHUP用来重开日志文件struct sigaction sa;sa.sa_handler = &handle_hup;sa.sa_flags = SA_RESTART;sigfillset(&sa.sa_mask);sigaction(SIGHUP, &sa, NULL);// 2) 若配置了daemon模式 -> 后台运行if (config->daemon) {if (daemon_init(config->daemon)) {exit(1);}}// 3) 各模块初始化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);// 4) 启动 logservice 服务struct skynet_context *ctx = skynet_context_new(config->logservice, config->logger);if (ctx == NULL) {fprintf(stderr, "Can't launch %s service\n", config->logservice);exit(1);}skynet_handle_namehandle(skynet_context_handle(ctx), "logger");// 5) 启动 bootstrap 服务 bootstrap(ctx, config->bootstrap);// 6) 启动多线程start(config->thread);// 7) 退出处理skynet_harbor_exit();skynet_socket_free();if (config->daemon) {daemon_exit(config->daemon);}
}

2.1 模块初始化

  1. skynet_harbor_init:与分布式/harbor机制有关(分布式集群的一部分)。
  2. skynet_handle_init:管理 “Handle -> Service” 映射。
  3. skynet_mq_init:初始化全局消息队列结构(global_queue)。
  4. skynet_module_init:C服务的模块管理,如加载 cpath 下的 .so
  5. skynet_timer_init:定时器初始化,创建 TI = timer_create_timer() 并记录当前系统时间。
  6. skynet_socket_init:socket层初始化,创建 socket_server
  7. skynet_profile_enable:若 config->profile 为真,打开性能分析。

2.2 启动初始服务

  • logservice:日志服务,用于记录日志(logger服务)。
  • bootstrap: 会启动launcher skynet.launch("snlua","launcher") 服务,后续用作lua 服务的启动器。

2.3 启动线程

start(config->thread);
  • Skynet 同时需要多个线程来协同工作:Monitor 线程Timer 线程Socket 线程、以及 N 个 Worker 线程
  • 这样就形成了一个 Skynet 进程 有多条并行线程,分别干不同的事(定时器、网络I/O、处理消息等)。
  • 具体见 static void start(int thread)

2.4 退出

  • 当线程全部 join() 完后,会执行 skynet_harbor_exitskynet_socket_free 等操作收尾。

3. start函数:创建并管理多条线程

static void
start(int thread) {pthread_t pid[thread+3];// 1) 创建 monitor 结构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 *));// 初始化互斥量, 条件变量// 2) 创建3条特殊线程create_thread(&pid[0], thread_monitor, m);create_thread(&pid[1], thread_timer, m);create_thread(&pid[2], thread_socket, m);// 3) 创建 worker 线程struct worker_parm wp[thread];for (i=0;i<thread;i++) {wp[i].m = m;wp[i].id = i;...create_thread(&pid[i+3], thread_worker, &wp[i]);}// 4) join 所有线程for (i=0;i<thread+3;i++) {pthread_join(pid[i], NULL);}free_monitor(m);
}

由此可见:

  • Monitor 线程thread_monitor
  • Timer 线程thread_timer
  • Socket 线程thread_socket
  • Worker 线程thread_worker (数量 = thread)

总线程数 = thread + 3

3.1 Monitor 线程

static void *
thread_monitor(void *p) {struct monitor * m = p;...for (;;) {// 定期检查 worker 是否卡死for (i=0;i<n;i++) {skynet_monitor_check(m->m[i]);}sleep(1);}return NULL;
}
  • 用于监控 Worker 线程是否卡死,通过 skynet_monitor_check 观测 worker 执行时间。
  • 如果检测到超长执行,会打印报警或采取措施(避免Worker永久阻塞)。

3.2 Timer 线程

static void *
thread_timer(void *p) {struct monitor * m = p;for (;;) {skynet_updatetime();       // 更新定时器skynet_socket_updatetime();// socket层时间更新wakeup(m,m->count-1);     // 唤醒所有线程( 让 worker 从 cond.wait 中唤醒 )usleep(2500);             // 2.5 ms 间隔...}...return NULL;
}
  • skynet_updatetime:增加 “逻辑时间” 并执行到期任务
  • skynet_socket_updatetime:驱动 socket server 中一些超时逻辑
  • wakeup:唤醒 Worker,防止他们陷入空闲
  • usleep(2500) => 每 2.5ms tick 一次

3.3 Socket 线程

static void *
thread_socket(void *p) {for (;;) {int r = skynet_socket_poll();if (r==0)break;if (r<0) {continue;}wakeup(m,0);}return NULL;
}
  • 这里循环调用 skynet_socket_poll(),监听网络事件(读写就绪、连接、断开等)。
  • r==0 表示 socket server 退出 => break
  • 每次有网络事件 => wakeup => 唤醒 Worker 线程去处理消息

3.4 Worker 线程

static void *
thread_worker(void *p) {struct worker_parm *wp = p;while (!m->quit) {// 1) 分发一条消息q = skynet_context_message_dispatch(sm, q, weight);if (q == NULL) {// 如果没有消息可处理 => sleeppthread_cond_wait(&m->cond, &m->mutex);}}return NULL;
}
  • Worker 线程主要做消息分发处理(从全局队列/本地队列取出消息 => 交给相应的服务context去执行。)
  • 如果没消息 => pthread_cond_wait => 休眠 => 等 Timer 或 Socket 线程唤醒。
  • weight 让某些线程能多处理几条消息(可实现不均衡分配, 保证核心Worker多干活)。

4. 结构化启动流程图

下图(示意)可帮助理解:

(1) main()|vskynet_globalinit() + skynet_env_init()|+--> parse config via Lua|vskynet_start(&config)|--- register SIGHUP|--- if daemon => daemon_init|--- skynet_*_init:|      - harbor_init|      - handle_init|      - mq_init|      - module_init|      - timer_init|      - socket_init||--- create logservice => "logger"|--- bootstrap => e.g. "snlua bootstrap"||--- start(#thread)|+-> create monitor thread+-> create timer thread+-> create socket thread+-> create N worker threads|+-> all threads join => end|vskynet_globalexit()|vreturn
  • main:解析 config, 调用 skynet_start
  • skynet_start:初始化模块/服务 => 启动多线程 => run => join => exit
  • 各个线程并行运作:
    • Monitor => 检测卡死
    • Timer => 定时器滴答 & 唤醒 worker
    • Socket => 处理网络事件
    • Worker => 真正执行 Lua 服务消息

5. 小结

  1. 主进程先解析配置,初始化一些全局,随后调用 skynet_start
  2. skynet_start 依次初始化 harbor、handle、mq、module、timer、socket…
  3. 启动logservice(记录日志)和bootstrap(初始Lua服务),最后启动多线程(monitor/timer/socket/worker)。
  4. 整个 Skynet 运行后,Timer 线程负责定时器 & 唤醒 Worker,Socket 线程负责网络事件,Worker 处理消息循环,Monitor检查 Worker 是否卡死。

通过这样一个启动流程,Skynet 建立起一个消息驱动的并发系统框架:

  • Worker 负责业务逻辑
  • Socket 处理IO
  • Timer 提供定时&超时功能
  • Monitor 监控

后续若要深入,可阅读每个线程对应函数(如 thread_timer, thread_worker)里更细节的流程,比如如何 dispatch 消息,如何在定时器中移位管理远期任务等。本篇作为阅读 Skynet 源码的起点,建立对整个启动过程多线程分工有一个全局认识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/6252.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端开发中的模拟后端与MVVM架构实践[特殊字符][特殊字符][特殊字符]

平时&#xff0c;后端可能不能及时给接口给前端进行数据调用和读取。这时候&#xff0c;前端想到进行模拟后端接口。本文将介绍如何通过vite-plugin-mock插件模拟后端接口&#xff0c;并探讨MVVM架构在前端开发中的应用。此外&#xff0c;我们还将讨论Vue2与Vue3的区别&#xf…

JAVA毕业设计210—基于Java+Springboot+vue3的中国历史文化街区管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue3的中国历史文化街区管理系统(源代码数据库)210 一、系统介绍 本项目前后端分离(可以改为ssm版本)&#xff0c;分为用户、工作人员、管理员三种角色 1、用户…

docker的前世今生

docker来自哪里&#xff1f; 从我们运维部署的历史来看&#xff0c;宿主机从最初的物理机到虚拟机&#xff0c;再到docker&#xff0c;一步步演进到现在。技术演进其实是为了解决当前技术的痛点&#xff0c;那我们来看看有哪些痛点以及如何克服痛点的。 物理机 一般来说&…

电脑办公技巧之如何在 Word 文档中添加文字或图片水印

Microsoft Word是全球最广泛使用的文字处理软件之一&#xff0c;它为用户提供了丰富的编辑功能来美化和保护文档。其中&#xff0c;“水印”是一种特别有用的功能&#xff0c;它可以用于标识文档状态&#xff08;如“草稿”或“机密”&#xff09;、公司标志或是版权信息等。本…

【机器学习案列】探索各因素对睡眠时间影响的回归分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

2024年度总结

迟来的2024年度总结&#xff0c;本文主要包括创作经历的回顾、个人成长与突破、以及职业与生活的平衡。 文章目录 1、 创作经历回顾2、 成长回顾3、 职业与生活的平衡4、 展望未来 1、 创作经历回顾 从高中开始就喜欢给别人解答疑问&#xff0c;大学学习模电、数电时&#xff…

vim在命令模式下的查找功能

/ab 从上往下 n 下一个 N 上一个 示例&#xff1a; 在命令模式下直接点击键盘上的/就可以进行查找&#xff0c;比如我要查找a&#xff0c;输入a后再回车&#xff0c;就可以检索出文件中所有和a有关的内容。 ?ab 从下往上 N 下一个 n 上一个 示例&#xff1a;和上图相同…

机器学习-使用梯度下降最小化均方误差

前面有一篇文章《机器学习-常用的三种梯度下降法》&#xff0c;这篇文章中对于均方误差的求偏导是错误的&#xff0c;为了澄清这个问题&#xff0c;我再写一篇文章来纠正一下&#xff0c;避免误导大家。 一、批量梯度下降法 我们用 批量梯度下降法 来求解一个简单的 线性回归…

基于quartz,刷新定时器的cron表达式

文章目录 前言基于quartz&#xff0c;刷新定时器的cron表达式1. 先看一下测试效果2. 实现代码 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

LabVIEW智能胎压监测

汽车行车安全是社会关注焦点&#xff0c;轮胎压力异常易引发交通事故&#xff0c;开发胎压监测系统可保障行车安全、降低事故发生率。 系统组成与特点 &#xff08;一&#xff09;硬件组成 BMP - 280 气体压力传感器&#xff1a;高精度、稳定性好、能耗低&#xff0c;适合车载…

C语言教程——文件处理(1)

目录 前言 二、什么是文件 2.1文件的概念 2.2程序文件 2.3数据文件 2.4文件名 2.5二进制文件和文本文件 三、文件操作 3.1文件指针 3.2文件的打开与关闭 四、文件的顺序读写 4.1fgetc 4.2fputc 4.3fputs 4.4fgets 总结 前言 我们知道电脑上有许许多多的文件&a…

【橘子ES】Kibana的分析能力Analytics简易分析

一、kibana是啥&#xff0c;能干嘛 我们经常会用es来实现一些关于检索&#xff0c;关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI&#xff0c;你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…

c#的tabControl控件实现自定义标签颜色

最近项目需要自定义tabControl控件颜色&#xff0c;而默认这个控件是不支持自定义标签颜色的&#xff0c;于是想办法实现了这个功能&#xff0c;效果如下图所示&#xff1a; 直接上代码&#xff1a; using System; using System.Collections.Generic; using System.ComponentM…

从零到一:Spring Boot 与 RocketMQ 的完美集成指南

1.Rocket的概念与原理 RocketMQ 是一款由阿里巴巴开源的分布式消息中间件&#xff0c;最初用于支持阿里巴巴的海量业务。它基于发布-订阅模型&#xff0c;具备高吞吐、低延迟、高可用和强一致性的特点&#xff0c;适用于消息队列、大规模数据流处理等场景。以下是对 RocketMQ …

Odoo免费开源ERP最佳业务实践:生产管理

文 / 开源智造&#xff08;OSCG&#xff09; Odoo亚太金牌服务 概述 Odoo是全球排名第一的免费开源ERP系统&#xff0c;以其强大的功能和模块化设计著称&#xff0c;适用于各种规模及类型的企业。Odoo集成了生产、采购、销售、库存、财务、人力资源、市场营销、电子商务等多个…

1.CSS的三大特性

css有三个非常重要的三个特性&#xff1a;层叠性、继承性、优先级 1.1 层叠性 想通选择器给设置想听的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一个冲突的样式。层叠性主要是解决样式冲突的问题。 <!DOCTYPE html> <html lang"en&…

【2024年华为OD机试】(A卷,200分)- 优雅子数组 (JavaScriptJava PythonC/C++)

一、问题描述 题目描述 如果一个数组中出现次数最多的元素出现大于等于 k 次&#xff0c;被称为 k-优雅数组&#xff0c;k 也可以被称为优雅阈值。 例如&#xff1a; 数组 [1, 2, 3, 1, 2, 3, 1] 是一个 3-优雅数组&#xff0c;因为元素 1 出现次数大于等于 3 次。数组 [1,…

电子应用设计方案102:智能家庭AI鱼缸系统设计

智能家庭 AI 鱼缸系统设计 一、引言 智能家庭 AI 鱼缸系统旨在为鱼类提供一个健康、舒适的生活环境&#xff0c;同时为用户提供便捷的管理和观赏体验。 二、系统概述 1. 系统目标 - 自动维持水质稳定&#xff0c;包括水温、酸碱度、硬度和溶氧量等关键指标。 - 智能投食&…

智能化加速标准和协议的更新并推动验证IP(VIP)在芯片设计中的更广泛应用

作者&#xff1a;Karthik Gopal, SmartDV Technologies亚洲区总经理 智权半导体科技&#xff08;厦门&#xff09;有限公司总经理 随着AI技术向边缘和端侧设备广泛渗透&#xff0c;芯片设计师不仅需要考虑在其设计中引入加速器&#xff0c;也在考虑采用速度更快和带宽更高的总…

Vue3.5 企业级管理系统实战(三):页面布局及样式处理 (Scss UnoCSS )

本章主要是关于整体页面布局及样式处理&#xff0c;在进行这一章代码前&#xff0c;先将前两章中的示例代码部分删除&#xff08;如Home.vue、About.vue、counter.ts、App.vue中引用等&#xff09; 1 整体页面布局 页面整体布局构成了产品的框架基础&#xff0c;通常涵盖主导…