From 91abd762cbeba1f9593ad0176283fdcbe1c26444 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Mon, 3 Feb 2020 14:00:47 -0500 Subject: [PATCH] Meta Mastery --- changes.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ multi/init.lua | 10 ++++---- test.lua | 28 ++++++++++++++++++-- 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/changes.md b/changes.md index 171e645..e765182 100644 --- a/changes.md +++ b/changes.md @@ -2,6 +2,76 @@ [TOC] Update 14.1.0 Bug Fixes and a change ------------- +# Full Update Example - I plan on doing full example for each future update. Every feature added gets touched and I litter it with comments. +```lua +package.path="?/init.lua;?.lua;"..package.path +multi,thread = require("multi"):init() +multi.OnLoad(function() + print("Code Loaded!") -- Connect to the load event +end) +t = os.clock() +co = 0 +multi.OnExit(function(n) + print("Code Exited: ".. os.clock()-t .." Count: ".. co) -- Lets print when things have ended +end) +test = thread:newFunction(function() + thread.sleep(1) -- Internally this throws a yield call which sends to the scheduler to sleep 1 second for this thread! + return 1,math.random(2,100) +end) +multi:newThread(function() + while true do + thread.skip() -- Even though we have a few metamethods "yielding" I used this as an example of things still happening and counting. It connects to the Code Exited event later on. + co = co + 1 + end +end) +-- We can get around the yielding across metamethods by using a threadedFunction +-- For Example +example = {} +setmetatable(example,{ + __newindex = function(t,k,v) -- Using a threaded function inside of a normal function + print("Inside metamethod",t,k,v) + local a,b = test().wait() -- This function holds the code and "yields" see comment inside the test function! + -- we should see a 1 seconde delay since the function sleeps for a second than returns + print("We did it!",a,b) + rawset(t,k,v) + -- This means by using a threaded function we can get around the yielding across metamethods. + -- This is useful if you aren't using luajit, or if you using lua in an enviroment that is on version 5.1 + -- There is a gotcha however, if using code that was meant to work with another coroutine based scheduler this may not work + end, + __index = thread:newFunction(function(t,k,v) -- Using a threaded function as the metamethod + -- This works by returning a table with a __call metamethod. Will this work? Will lua detect this as a function or a table? + thread.sleep(1) + return "You got a string" + end,true) -- Tell the code to force a wait and to identify as a function. We need to do this for metamethods + -- If we don't pass true this is a table with a __call metamethod +}) +example["test"] = "We set a variable!" +print(example["test"]) +print(example.hi) +-- When not in a threaded enviroment at root level we need to tell the code that we are waiting! Alternitavely after the function argument we can pass true to force a wait +c,d = test().wait() +print(c,d) +a,b = 6,7 +multi:newThread(function() + -- a,b = test().wait() -- Will modify Global + -- when wait is used the special metamethod routine is not triggered and variables are set as normal + a,b = test() -- Will modify GLocal + -- the threaded function test triggers a special routine within the metamethod that alters the thread's enviroment instead of the global enviroment. + print("Waited:",a,b) + --This returns instantly even though the function isn't done! + test().connect(function(a,b) + print("Connected:",a,b) + os.exit() + end) + -- This waits for the returns since we are demanding them +end) +multi:mainloop() +``` +# Changed: +- thread:newFunction(func,holdme) -- Added an argument holdme to always force the threaded funcion to wait. Meaning you don't need to tell it to func().wait() or func().connect() +- multi:newConnection(protect,callback,kill) -- Added the kill argument. Makes connections work sort of like a stack. Pop off the connections as they get called. So a one time connection handler. + - I'm not sure callback has been documented in any form. callback gets called each and everytime conn:Fire() gets called! As well as being triggered for each connfunc that is part of the connection. + # Added: - multi.OnLoad(func) -- A special connection that allows you to connect to the an event that triggers when the multi engine starts! This is slightly different from multi.PreLoad(func) Which connects before any variables have been set up in the multi table, before any settings are cemented into the core. In most cases they will operate exactly the same. This is a feature that was created with module creators in mind. This way they can have code be loaded and managed before the main loop starts. - multi.OnExit(func) -- A special connection that allows you to connect onto the lua state closing event. diff --git a/multi/init.lua b/multi/init.lua index bee6bdc..b929389 100644 --- a/multi/init.lua +++ b/multi/init.lua @@ -1476,9 +1476,8 @@ function multi.holdFor(n,func) end end) end -function thread:newFunction(func) - local c = {Type = "tfunc"} - c.__call = function(self,...) +function thread:newFunction(func,holdme) + return function(self,...) local rets, err local function wait(no) if thread.isThread() and not (no) then @@ -1499,6 +1498,9 @@ function thread:newFunction(func) local t = multi:newThread("TempThread",func,...) t.OnDeath(function(self,status,...) rets = {...} end) t.OnError(function(self,e) err = e end) + if holdme then + return wait() + end local temp = { isTFunc = true, wait = wait, @@ -1509,8 +1511,6 @@ function thread:newFunction(func) } return temp,temp,temp,temp,temp,temp,temp end - setmetatable(c,c) - return c end function thread.run(func) local threaddata,t2,t3,t4,t5,t6 diff --git a/test.lua b/test.lua index bb06d4c..0aabc10 100644 --- a/test.lua +++ b/test.lua @@ -9,7 +9,7 @@ multi.OnExit(function(n) print("Code Exited: ".. os.clock()-t .." Count: ".. co) end) test = thread:newFunction(function() - thread.sleep(1) + thread.sleep(1) -- Internally this throws a yield call which sends to the scheduler to sleep 1 second for this thread! return 1,math.random(2,100) end) multi:newThread(function() @@ -18,7 +18,31 @@ multi:newThread(function() co = co + 1 end end) --- When not in a threaded enviroment at root level we need to tell the code that we are waiting! +-- We can get around the yielding across metamethods by using a threadedFunction +-- For Example +example = {} +setmetatable(example,{ + __newindex = function(t,k,v) -- Using a threaded function inside of a normal function + print("Inside metamethod",t,k,v) + local a,b = test().wait() -- This function holds the code and "yields" see comment inside the test function! + -- we should see a 1 seconde delay since the function sleeps for a second than returns + print("We did it!",a,b) + rawset(t,k,v) + -- This means by using a threaded function we can get around the yielding across metamethods. + -- This is useful if you aren't using luajit, or if you using lua in an enviroment that is on version 5.1 + -- There is a gotcha however, if using code that was meant to work with another coroutine based scheduler this may not work + end, + __index = thread:newFunction(function(t,k,v) -- Using a threaded function as the metamethod + -- This works by returning a table with a __call metamethod. Will this work? Will lua detect this as a function or a table? + thread.sleep(1) + return "You got a string" + end,true) -- Tell the code to force a wait and to identify as a function. We need to do this for metamethods + -- If we don't pass true this is a table with a __call metamethod +}) +example["test"] = "We set a variable!" +print(example["test"]) +print(example.hi) +-- When not in a threaded enviroment at root level we need to tell the code that we are waiting! Alternitavely after the function argument we can pass true to force a wait c,d = test().wait() print(c,d) a,b = 6,7