当前位置: 首页 > article >正文

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 源码的起点,建立对整个启动过程多线程分工有一个全局认识。

相关文章:

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

Skynet 启动主流程分析 Skynet 是一个轻量级、高并发的服务器框架。它在启动时会进行一系列初始化操作&#xff0c;并启动多个不同功能的线程&#xff08;Monitor、Timer、Worker、Socket&#xff09;&#xff0c;从而实现消息分发、定时器、网络I/O等核心功能。本文主要从 ma…...

活动回顾和预告|微软开发者社区 Code Without Barriers 上海站首场活动成功举办!

Code Without Barriers 上海活动回顾 Code Without Barriers&#xff1a;AI & DATA 深入探索人工智能与数据如何变革行业 2025年1月16日&#xff0c;微软开发者社区 Code Without Barriers &#xff08;CWB&#xff09;携手 She Rewires 她原力在大中华区的首场活动“AI &…...

Workerman和Swoole有什么区别

Workerman和Swoole都是PHP的socket服务器框架&#xff0c;它们之间存在一些显著的区别&#xff0c;主要体现在以下几个方面&#xff1a; 一、实现语言与性能 Workerman&#xff1a;使用纯PHP实现。由于PHP本身的性能限制&#xff0c;Workerman在某些方面可能不如C语言实现的框…...

项目部署(springboot项目)

1、安装Nginx&#xff0c;并开启 2、前端项目打包&#xff1a;npm run build:prod--->dist 3、后端项目打包&#xff1a;install--->xxx.jar 4、开放需要的端口号&#xff1a;比如我的后端项目端口号为8282&#xff0c;则需要防火墙和服务器同时开发8282端口 5、将di…...

从0到1:C++ 开启游戏开发奇幻之旅(一)

目录 为什么选择 C 进行游戏开发 性能卓越 内存管理精细 跨平台兼容性强 搭建 C 游戏开发环境 集成开发环境&#xff08;IDE&#xff09; Visual Studio CLion 图形库 SDL&#xff08;Simple DirectMedia Layer&#xff09; SFML&#xff08;Simple and Fast Multim…...

Python-列表

3.1 列表是什么 在Python中&#xff0c;列表是一种非常重要的数据结构&#xff0c;用于存储一系列有序的元素。列表中的每个元素都有一个索引&#xff0c;索引从0开始。列表可以包含任何类型的元素&#xff0c;包括其他列表。 # 创建一个列表my_list [1, 2, 3, four, 5.0]…...

下载Visual Studio Community 2019

官方链接如下&#xff1a;Visual Studio Community 2019下载链接 https://learn.microsoft.com/zh-cn/visualstudio/releases/2019/system-requirements#download 目前官方仅建议2022版&#xff0c;已经关闭vs2019等旧版本&#xff0c;哪天开放了&#xff0c;记得踢我一下。 …...

MongoDB平替数据库对比

背景 项目一直是与实时在线监测相关&#xff0c;特点数据量大&#xff0c;读写操作大&#xff0c;所以选用的是MongoDB。但按趋势来讲&#xff0c;需要有一款国产数据库可替代&#xff0c;实现信创要求。选型对比如下 1. IoTDB 这款是由清华大学主导的开源时序数据库&#x…...

c++ set/multiset 容器

1. set 基本概念 简介&#xff1a; 所有元素都会在插入时自动排序本质&#xff1a; set/multiset属于关联式容器&#xff0c;底层结构是用二叉树实现。set 和 multiset 区别&#xff1a; set容器不允许有重复的元素。 multiset允许有重复的元素。2. set 构造和赋值 构造&a…...

SCRM在企业私域流量与客户管理中的变革之路探索

内容概要 在当今数字化高速发展的时代&#xff0c;SCRM&#xff08;社交客户关系管理&#xff09;作为一种新的管理工具&#xff0c;正逐渐成为企业私域流量管理和客户关系维护的重要基石。它不仅仅是一种软件工具&#xff0c;更是一种整合客户数据和关系管理的全新思维方式。…...

爱的魔力转圈圈,基于carsim与simulink模拟仰望u8原地调头

仰望U8原地转向的示意图如下&#xff0c;不动方向盘的情况下&#xff0c;车可以自己转圈圈&#xff1a; 原理也很简单&#xff0c;仰望u8是四轮驱动&#xff0c;四个轮子都单独由四个轮边电机驱动。主要我们将左右的车轮轮速控制成左右两边轮速相同&#xff0c;但是方向相反&am…...

2025多目标优化创新路径汇总

多目标优化是当下非常热门且有前景的方向&#xff01;作为AI领域的核心技术之一&#xff0c;其专注于解决多个相互冲突的目标的协同优化问题&#xff0c;核心理念是寻找一组“不完美但均衡”的“帕累托最优解”。在实际中&#xff0c;几乎处处都有它的身影。 但随着需求场景的…...

输出九九乘法表

# 题目&#xff1a;输出九九乘法表 #(1) for i in range(1,10): #行数&#xff0c;1到9for j in range(1,10): # 列数1到9resulti*jprint(f"{i}*{j}{result}",end"\t")print("\n")#(2) for i in range(1,10): #行数for j in range(1,i1): #列数1…...

基于微信小程序的新闻资讯系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

vim如何解决‘’文件非法关闭后,遗留交换文件‘’的问题

过程描述&#xff1a; 由于我修改文件时&#xff08;一定得修改了文件&#xff0c;不做任何修改不会产生这个问题&#xff09;的非法关闭&#xff0c;比如直接关闭虚拟机&#xff0c;或者直接断开远程工具的远程连接&#xff0c;产生了以下遗留交换文件的问题&#xff1a; 点击…...

vue3+elementPlus之后台管理系统(从0到1)(day4-完结)

面包屑 创建一个面包屑组件 将路由导入然后格式化map对象 key-value 将当前路由的key和value获取然后存入list数组中 遍历list数据&#xff0c;渲染内容 <!--BreadcrumbCom.vue--> <template><el-breadcrumb separator">"><el-breadcrum…...

基于Flask的旅游系统的设计与实现

【Flask】基于Flask的旅游系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统采用Python作为后端开发语言&#xff0c;结合前端Bootstrap框架&#xff0c;为用户提供了丰富…...

代码随想录31

目录 leetcode135.分发糖果 思路&#xff1a; leetcode860.柠檬水找零 思路&#xff1a;就是一个个遍历然后判断&#xff0c;用哈希表存储数。 leetcode406.根据身高重建队列 leetcode135.分发糖果 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需…...

【公因数匹配——暴力、(质)因数分解、哈希】

题目 暴力代码&#xff0c;Acwing 8/10&#xff0c;官网AC #include <bits/stdc.h> using namespace std; const int N 1e610; vector<int> nums[N]; int main() {ios::sync_with_stdio(0);cin.tie(0);int n;cin >> n;for(int i 1; i < n; i){int x;ci…...

WPS数据分析000010

基于数据透视表的内容 一、排序 手动调动 二、筛选 三、值显示方式 四、值汇总依据 五、布局和选项 不显示分类汇总 合并居中带标签的单元格 空单元格显示 六、显示报表筛选页...

RabbitMQ 架构分析

文章目录 前言一、RabbitMQ架构分析1、Broker2、Vhost3、Producer4、Messages5、Connections6、Channel7、Exchange7、Queue8、Consumer 二、消息路由机制1、Direct Exchange2、Topic Exchange3、Fanout Exchange4、Headers Exchange5、notice5.1、备用交换机&#xff08;Alter…...

127周一复盘 (165)玩法与难度思考

1.上午测试&#xff0c;小改了点东西&#xff0c; 基本等于啥也没干。 匆忙赶往车站。 从此进入春节期间&#xff0c;没有开发&#xff0c;而思考与设计。 2.火车上思考玩法与难度的问题。 目前的主流作法实际上并不完全符合不同玩家的需求&#xff0c; 对这方面还是要有自…...

Spring--SpringMVC使用(接收和响应数据、RESTFul风格设计、其他扩展)

SpringMVC使用 二.SpringMVC接收数据2.1访问路径设置2.2接收参数1.param和json2.param接收数据3 路径 参数接收4.json参数接收 2.3接收cookie数据2.4接收请求头数据2.5原生api获取2.6共享域对象 三.SringMVC响应数据3.1返回json数据ResponseBodyRestController 3.2返回静态资源…...

git Bash通过SSH key 登录github的详细步骤

1 问题 通过在windows 终端中的通过git登录github 不再是通过密码登录了&#xff0c;需要本地生成一个密钥&#xff0c;配置到gihub中才能使用 2 步骤 &#xff08;1&#xff09;首先配置用户名和邮箱 git config --global user.name "用户名"git config --global…...

在计算机上本地运行 Deepseek R1

Download Ollama on Linux Download Ollama on Windows Download Ollama on macOS Deepseek R1 是一个强大的人工智能模型&#xff0c;在科技界掀起了波澜。它是一个开源语言模型&#xff0c;可以与 GPT-4 等大玩家展开竞争。但更重要的是&#xff0c;与其他一些模型不同&…...

基于51单片机和ESP8266(01S)、LCD1602、DS1302、独立按键的WiFi时钟

目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、延时2、定时器03、串口通信4、DS13025、LCD16026、独立按键 四、主函数总结 系列文章目录 前言 之前做了一个WiFi定时器时钟&#xff0c;用八位数码管进行显示&#xff0c;但是定时器时钟的精度较低&#xff0…...

机器学习 ---逻辑回归

逻辑回归是属于机器学习里面的监督学习&#xff0c;它是以回归的思想来解决分类问题的一种非常经典的二分类分类器。由于其训练后的参数有较强的可解释性&#xff0c;在诸多领域中&#xff0c;逻辑回归通常用作 baseline 模型&#xff0c;以方便后期更好的挖掘业务相关信息或提…...

拟合损失函数

文章目录 拟合损失函数一、线性拟合1.1 介绍1.2 代码可视化1.2.1 生成示例数据1.2.2 损失函数1.2.3 绘制三维图像1.2.4 绘制等高线1.2.5 损失函数关于斜率的函数 二、 多变量拟合2.1 介绍2.2 代码可视化2.2.1 生成示例数据2.2.2 损失函数2.2.3 绘制等高线 三、 多项式拟合3.1 介…...

【C++基础】多线程并发场景下的同步方法

如果在多线程程序中对全局变量的访问没有进行适当的同步控制&#xff08;例如使用互斥锁、原子变量等&#xff09;&#xff0c;会导致多个线程同时访问和修改全局变量时发生竞态条件&#xff08;race condition&#xff09;。这种竞态条件可能会导致一系列不确定和严重的后果。…...

Linux常见问题解决方法--1

常见安全工具、设备 工具 端口及漏洞扫描&#xff1a;Namp、Masscan 抓包&#xff1a;Wireshark&#xff0c;Burpsuite、Fiddler、HttpCanary Web自动化安全扫描&#xff1a;Nessus、Awvs、Appscan、Xray 信息收集&#xff1a;Oneforall、hole 漏洞利用&#xff1a;MSF、…...