skynet
未读launcher的创建目录
当前工作线程完成步骤1
可能另一个工作线程完成步骤2
launcher服务是一个snlua服务。
当调用skynet.newservice请求创建某个服务的时候,实际上会把创建请求发送到launcher服务。launcher来真正启动一个目标服务。launcher本身又是怎么启动的?他是在bootstrap服务里面启动的。看看代码 11行。
bootstrap服务也是一个snlua服务
1234567891011121314151617181920212223242526--bootstrap.lualocal skynet = require "skynet"local harbor = require "skynet.harbor"local service = require "skynet.service"require "skynet.manager" -- import skynet.launch, ...skynet.start(function() loc ...
skynet
未读snlua服务的创建在服务间请求和响应的时候,在main服务里启动了一个db服务。
12345678910111213--main.lualocal skynet = require "skynet"skynet.start(function()--lua服务的入口函数 local db = skynet.newservice("db")--启动一个db服务 local key = "zhangsan" local age = skynet.call(db, "lua", "GET",key) --发送 lua类型 的请求给db服务,然后等待对方回应 skynet.exit() end)
调用 skynet.newservice("db")启动了一个db服务。当调用 skynet.newservice 的时候,当前协程会挂起。他会发送一个请求给 launcher 服务,表示请启动一个db服务。 launcher 服务收到请求后,会启动创建db服务。当db服务 ...
skynet
未读Skynet_处理队列消息工作线程 thread_worker 在设置完参数后,服务队列的消息在 while 循环中不断被处理和分发:
12345678910111213141516171819202122232425262728static void *thread_worker(void *p) { struct worker_parm *wp = p; int id = wp->id; int weight = wp->weight; struct monitor *m = wp->m; struct skynet_monitor *sm = m->m[id]; skynet_initthread(THREAD_WORKER); struct message_queue * q = NULL; while (!m->quit) { q = skynet_context_message_dispatch(sm, q, weight);//next if (q == NULL) {//没有消息处理 就休息一下 等待唤醒 ...
skynet
未读Skynet_db服务处理请求db服务处理main服务发送过来的请求 db 服务指定的lua文件:
12345678910111213141516171819202122232425262728--db.lualocal skynet = require "skynet"require "skynet.manager" -- import skynet.registerlocal db = {--保存了年龄 zhangsan = 12, lisi = 33, wangwu = 4}local command = {}function command.GET(key) return db[key]endskynet.start(function() skynet.dispatch("lua", function(session, address, cmd, ...)--对应lua消息注册任务函数,专门处理 lua类型 的请求 local f = command[c ...
skynet
未读Lua函数尾调用尾调用的基本概念尾调用(Tail Call)是指一个函数的最后一个动作是调用另一个函数,并且不需要保留当前函数的执行环境。这种调用方式在Lua中具有特殊重要性,因为Lua解释器会对尾调用进行优化,避免不必要的栈空间使用。
1234-- 正确的尾调用示例function f(x) return g(x) -- 尾调用:最后一步操作且直接返回结果end
与普通函数调用不同,尾调用使Lua编译器能够重用当前的栈帧,而不是创建一个新的调用帧。这意味着尾调用不会增加栈深度,即使无限递归也不会导致栈溢出。这一特性使得Lua能够高效地处理递归算法和状态机实现,尤其在使用深度递归或长期运行的状态转换时显得尤为重要。
理解尾调用的关键是认识到它不仅仅是”函数最后一行调用”,而是函数最后一步操作。这意味着在调用后,当前函数不再需要执行任何计算或保留任何状态。这种特性使得Lua可以像执行goto语句一样处理尾调用,直接跳转到新函数而不保留返回地址。
调用栈与调用帧的原理要理解尾调用优化,首先需要了解函数调用的底层机制。在大多数编程语言中,函数调用使用调用栈(Call Stack)来 ...
skynet
未读Skynet_logger服务日志服务使用举例:默认是写到stdout
1skynet.error("hello world")
写日志主要分三步:
logger日志服务创建
把日志转变成 skynet_message 然后push到日志服务队列
日志服务处理消息时把日志提取出来,写入文件或者标准输出。
logger服务创建 skynet_main :读取配置中的日志服务(主要展示logger配置的获取)
config.logger :保存日志的文件名字
config.logservice :默认日志模块
12345678910111213141516171819202122232425262728intmain(int argc, char *argv[]) { struct skynet_config config; struct lua_State *L = luaL_newstate();//生成luastate的目的主要是读取配置文件中的配置项 luaL_openlibs(L); // 链接 lua 库 int err = luaL ...
Skynet_协程协程的基本概念每个lua虚拟机中可以有多个协程协调工作,但虚拟机中永远只有一个协程在工作。
情况一:
协程都会绑定一个 主体函数 。如果协程还没有运行过,直接调用 coroutine_resume(co,...) 就会导致协程开始运行,即开始执行主体函数,主体函数收到的参数就是上面的 ... 。调用者此时处于阻塞等待的状态。当主体函数执行完成的时候, coroutine_resume 也返回了,对于调用者来说, coroutine_resume 返回值就是主体函数的返回值。
12345678910local co = coroutine_create( function(money) --绑定了一个匿名主体函数 -- dosomething return "绫罗绸缎" --ret的返回值 end)local ok,ret = coroutine_resume(co,955) --当协程co执行的时候,当前调用者是阻塞的,即不能立即执行第10行print(ok,ret)
ok ...
skynet
未读Skynet_服务间请求和响应snlua服务启动的基本知识 lua 服务跟 logger 服务的工作模式在c层看来都是一样的,即都有一个队列,然后不断的从队列中取出消息,然后处理掉消息。当然这两者属于不同模块。
lua 服务可以认为跟 logger 服务最大的区别是:
取出消息->lua服务回调函数-> skynet.dispatch_message
取出消息->logger服务回调函数
之前创建一个 logger 服务是在底层调用 skynet_context_new(const char * name, const char *param) , name 就是模块名字 logger , param 默认是 NULL 。实际上创建一个 lua 服务,也是调用这个函数,name 就是 snlua , param 是一个 lua 文件名.
但实际上服务创建是通过 skynet.newservice 创建的。这个函数最终一样会调用底层的 skynet_context_new 来创建服务。skynet进程启动后,就会启动一个 bootstrap 服务, boots ...
C_函数函数是 C 语言的基本构建组件 (building blocks),可以把一个大程序划分为小的组件,从而降低程序的复杂度。使用函数还可以避免编写重复的代码,从而提高程序的可维护性。
函数的定义在C语言中,函数的定义:
返回类型:可以是基本数据类型,也可以是结构体、指针等复合数据类型。不能返回数组,除此之外,函数可以返回任意类型的值。如返回值类型为 void,则函数没有返回值。
函数名称:用于在程序中调用该函数。
参数列表:可以是零个或多个,需要在每个形式参数前面指定它的类型,并且参数之间用逗号分隔。如果函数没有形式参数,应该标明为 void。
函数体:包含声明和语句。在函数体内声明的变量只属于此函数,其它函数不能访问和修改这些变量。
12345return-type function-name (parameters) { declarations statements}
函数调用函数调用由函数名和实际参数 (argument) 列表组成。如:average(x, y)。
非 void 函数调用会产生一个值,该值可以存储在变量中,用于测试、显示,或 ...
C_历史C语言的起源C 语言是贝尔实验室的Ken Thompson、 Dennis Ritchie等人开发的UNIX 操作系统的 “副产品”。Thompson独自编写出了最初版本的 UNIX 操作系统,这套系统运行在只有 16KB内存的 DEC PDP -7计算机上。
UNIX系统最初是用汇编语言编写的,用汇编语言编写的程序往往难以调试和扩展。 Thompson意识到需要用一种更加高级的编程语言来完成 UNIX 系统未来的开发,于是 他设计了一种小型语言—— B语言。 B语言是在BCPL语言(20世纪60年代中期产生的一 种系统编程语言)的基础上开发的,而BCPL语言又可以追溯到最早的语言之一 —— Algol 60。
不久, Ritchie也加入到UNIX项目中,并且开始着手用B语言编写程序。 1970年,贝尔 实验室为UNIX项目争取到一台PDP -11计算机。当B语言经过改进并能够在PDP -11计 算机上运行后, Thompson用B语言重新编写了部分UNIX代码。到了1971年, B语言已 经明显不适合PDP -11计算机了,于是Ritchie着手开发B语 ...


