working on 1.14.4
This commit is contained in:
parent
296d56d233
commit
689133e71f
33
changes.md
33
changes.md
@ -1,5 +1,38 @@
|
||||
# Changes
|
||||
[TOC]
|
||||
Update 14.0.0 Consistency and stability
|
||||
-------------
|
||||
Added:
|
||||
- multi.init() -- Initlizes the library! Must be called for multiple files to have the same handle. Example below
|
||||
- thread.holdFor(NUMBER sec, FUNCTION condition) -- Works like hold, but timesout when a certain amount of time has passed!
|
||||
- thread.holdWithin(NUMBER; cycles,FUNCTION; condition) -- Holds until the condition is met! If the number of cycles passed is equal to cycles, hold will return a timeout error
|
||||
**Note:** when hold has a timeout the first argument will return nil and the second atgument will be TIMEOUT, if not timed out hold will return the values from the conditions
|
||||
|
||||
Fixed:
|
||||
- Connections had a preformance issue where they would create a non function when using connection.getConnection() of a non existing label.
|
||||
- An internal mismanagement of the treads scheduler was fixed. Now it should be quicker and free of bugs
|
||||
- Thread error management is the integrations was not properly implemented. This is now fixed
|
||||
-
|
||||
|
||||
Changed:
|
||||
- Ties in to the new function that has been added multi.init()
|
||||
```lua
|
||||
local multi, thread = require("multi").init() -- The require multi function still returns the multi object like before
|
||||
```
|
||||
Note: Using init allows you to get access to the thread handle. This was done because thread was modifying the global space as well as multi. I wanted to not modify the global space anymore.
|
||||
internally most of your code can stay the same, you only need to change how the library is required. I do toy a bit with the global space, buy I use a variable name that is invalid as a variable name. The variable name is $multi. This is used internally to keep some records and maintain a clean space
|
||||
|
||||
Also when using intergrations things now look more consistant.
|
||||
```lua
|
||||
local multi, thread = require("multi").init()
|
||||
local GLOBSL, THREAD = require("multi.integration.lanesManager").init() -- or whichever manager you are using
|
||||
local nGLOBAL, nTHREAD = require("multi.intergration.networkManager).inti()
|
||||
```
|
||||
Note: You can mix and match integrations together. You can create systemthreads within network threads, and you can also create cotoutine based threads within bothe network and system threads. This gives you quite a bit of flexibility to create something awesome.
|
||||
|
||||
Going forward:
|
||||
- Sterlization is still being worked on. I was planning of having a way to save state of multi objects and such, but that isn't possible without knowing how your code is strutured or if it is even made to handle something like that. So I decided on giving a tostirng/tofile method for each multi object as well as a fromstring/fromfile method for use. This is technically in the code already, but not documented. It has actually been in the code for a while, but its not done just yet and I want to make it perfect before sending it out.
|
||||
|
||||
Update 13.1.0 Bug fixes and features added
|
||||
-------------
|
||||
Added:
|
||||
|
||||
@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
local multi = require("multi")
|
||||
local multi, thread = require("multi").init()
|
||||
os.sleep = love.timer.sleep
|
||||
multi.drawF = {}
|
||||
function multi:onDraw(func, i)
|
||||
@ -38,14 +38,18 @@ multi.OnDraw = multi:newConnection()
|
||||
multi.OnTextInput = multi:newConnection()
|
||||
multi.OnUpdate = multi:newConnection()
|
||||
multi.OnQuit = multi:newConnection()
|
||||
multi.OnPreLoad(function()
|
||||
multi.OnPreLoad(
|
||||
function()
|
||||
local function Hook(func, conn)
|
||||
if love[func] ~= nil then
|
||||
love[func] = Library.convert(love[func])
|
||||
love[func]:inject(function(...)
|
||||
love[func]:inject(
|
||||
function(...)
|
||||
conn:Fire(...)
|
||||
return {...}
|
||||
end,1)
|
||||
end,
|
||||
1
|
||||
)
|
||||
elseif love[func] == nil then
|
||||
love[func] = function(...)
|
||||
conn:Fire(...)
|
||||
@ -62,15 +66,20 @@ multi.OnPreLoad(function()
|
||||
Hook("draw", multi.OnDraw)
|
||||
Hook("textinput", multi.OnTextInput)
|
||||
Hook("update", multi.OnUpdate)
|
||||
multi.OnDraw(function()
|
||||
multi.OnDraw(
|
||||
function()
|
||||
for i = 1, #multi.drawF do
|
||||
love.graphics.setColor(255, 255, 255, 255)
|
||||
multi.drawF[i]()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
multi.OnQuit(function()
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
multi.OnQuit(
|
||||
function()
|
||||
multi.Stop()
|
||||
love.event.quit()
|
||||
end)
|
||||
end
|
||||
)
|
||||
return multi
|
||||
|
||||
@ -25,6 +25,9 @@ local bin = pcall(require,"bin")
|
||||
local multi = {}
|
||||
local clock = os.clock
|
||||
local thread = {}
|
||||
if not _G["$multi"] then
|
||||
_G["$multi"] = {multi=multi,thread=thread}
|
||||
end
|
||||
multi.Version = "13.1.0"
|
||||
multi._VERSION = "13.1.0"
|
||||
multi.stage = "stable"
|
||||
@ -78,6 +81,9 @@ multi.PriorityTick=1 -- Between 1, 2 and 4
|
||||
multi.Priority=multi.Priority_High
|
||||
multi.threshold=256
|
||||
multi.threstimed=.001
|
||||
function multi.init()
|
||||
return _G["$multi"].multi,_G["$multi"].thread
|
||||
end
|
||||
function multi.queuefinal(self)
|
||||
self:Destroy()
|
||||
if self.Parent.Mainloop[#self.Parent.Mainloop] then
|
||||
@ -758,6 +764,9 @@ function multi:newConnector()
|
||||
local c = {Type = "connector"}
|
||||
return c
|
||||
end
|
||||
local CRef = {
|
||||
Fire = function() end
|
||||
}
|
||||
function multi:newConnection(protect,func)
|
||||
local c={}
|
||||
c.callback = func
|
||||
@ -802,11 +811,9 @@ function multi:newConnection(protect,func)
|
||||
return self
|
||||
end
|
||||
c.FConnect=c.fConnect
|
||||
function c:getConnection(name,ingore)
|
||||
if ingore then
|
||||
return self.connections[name] or {
|
||||
Fire=function() return end -- if the connection doesn't exist lets call all of them or silently ignore
|
||||
}
|
||||
function c:getConnection(name,ignore)
|
||||
if ignore then
|
||||
return self.connections[name] or CRef
|
||||
else
|
||||
return self.connections[name] or self
|
||||
end
|
||||
@ -1489,6 +1496,10 @@ function thread.hold(n)
|
||||
thread._Requests()
|
||||
return coroutine.yield({"_hold_",n or function() return true end})
|
||||
end
|
||||
function thread.holdFor(sec,n)
|
||||
thread._Requests()
|
||||
return coroutine.yield({"_holdF_", sec, n or function() return true end})
|
||||
end
|
||||
function thread.skip(n)
|
||||
thread._Requests()
|
||||
if not n then n = 1 elseif n<1 then n = 1 end
|
||||
@ -1652,6 +1663,13 @@ function multi.initThreads()
|
||||
threads[i].task = "hold"
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_holdF_" then
|
||||
threads[i].sec = ret[2]
|
||||
threads[i].func = ret[3]
|
||||
threads[i].task = "holdF"
|
||||
threads[i].time = clock()
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1684,8 +1702,19 @@ function multi.initThreads()
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
end
|
||||
elseif threads[i].task == "holdF" then
|
||||
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
|
||||
if t0 then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
elseif clock() - threads[i].time>=threads[i].sec then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
t0 = nil
|
||||
t1 = "TIMEOUT"
|
||||
end
|
||||
if threads[i].__ready then
|
||||
end
|
||||
if threads[i] and threads[i].__ready then
|
||||
threads[i].__ready = false
|
||||
_,ret=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
|
||||
end
|
||||
@ -1724,6 +1753,13 @@ function multi:threadloop()
|
||||
threads[i].task = "hold"
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
elseif ret[1]=="_holdF_" then
|
||||
threads[i].sec = ret[2]
|
||||
threads[i].func = ret[3]
|
||||
threads[i].task = "holdF"
|
||||
threads[i].time = clock()
|
||||
threads[i].__ready = false
|
||||
ret = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1753,6 +1789,17 @@ function multi:threadloop()
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
end
|
||||
elseif threads[i].task == "holdF" then
|
||||
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
|
||||
if t0 then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
elseif clock() - threads[i].time>=threads[i].sec then
|
||||
threads[i].task = ""
|
||||
threads[i].__ready = true
|
||||
t0 = nil
|
||||
t1 = "TIMEOUT"
|
||||
end
|
||||
end
|
||||
if threads[i].__ready then
|
||||
threads[i].__ready = false
|
||||
@ -2550,7 +2597,4 @@ end
|
||||
function multi:setDefualtStateFlag(opt)
|
||||
--
|
||||
end
|
||||
if not(multi.Version == "13.2.0" or multi.Version == "14.0.0") then
|
||||
_G.thread = thread
|
||||
end
|
||||
return multi, thread
|
||||
return multi
|
||||
|
||||
@ -22,18 +22,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
package.path = "?/init.lua;?.lua;" .. package.path
|
||||
local multi, thread = require("multi").init() -- get it all and have it on all lanes
|
||||
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel
|
||||
return {
|
||||
init = function()
|
||||
return multi.integration.GLOBAL, multi.integration.THREAD
|
||||
end
|
||||
}
|
||||
end
|
||||
function os.getOS()
|
||||
if package.config:sub(1,1)=='\\' then
|
||||
return 'windows'
|
||||
if package.config:sub(1, 1) == "\\" then
|
||||
return "windows"
|
||||
else
|
||||
return 'unix'
|
||||
return "unix"
|
||||
end
|
||||
end
|
||||
-- Step 1 get lanes
|
||||
lanes = require("lanes").configure()
|
||||
local multi, thread = require("multi") -- get it all and have it on all lanes
|
||||
multi.SystemThreads = {}
|
||||
local thread = thread
|
||||
multi.isMainThread = true
|
||||
function multi:canSystemThread()
|
||||
return true
|
||||
@ -46,14 +52,17 @@ local __GlobalLinda = lanes.linda() -- handles global stuff
|
||||
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
|
||||
-- For convenience a GLOBAL table will be constructed to handle requests
|
||||
local GLOBAL = {}
|
||||
setmetatable(GLOBAL,{
|
||||
setmetatable(
|
||||
GLOBAL,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return __GlobalLinda:get(k)
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
__GlobalLinda:set(k, v)
|
||||
end,
|
||||
})
|
||||
end
|
||||
}
|
||||
)
|
||||
-- Step 3 rewrite the thread methods to use Lindas
|
||||
local THREAD = {}
|
||||
function THREAD.set(name, val)
|
||||
@ -63,10 +72,10 @@ function THREAD.get(name)
|
||||
__GlobalLinda:get(name)
|
||||
end
|
||||
local function randomString(n)
|
||||
local str = ''
|
||||
local str = ""
|
||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
for i = 1, n do
|
||||
str = str..''..strings[math.random(1,#strings)]
|
||||
str = str .. "" .. strings[math.random(1, #strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
@ -75,7 +84,9 @@ function THREAD.waitFor(name)
|
||||
math.randomseed(os.time())
|
||||
__SleepingLinda:receive(.001, randomString(12))
|
||||
end
|
||||
repeat wait() until __GlobalLinda:get(name)
|
||||
repeat
|
||||
wait()
|
||||
until __GlobalLinda:get(name)
|
||||
return __GlobalLinda:get(name)
|
||||
end
|
||||
function THREAD.testFor(name, val, sym)
|
||||
@ -114,7 +125,9 @@ function THREAD.hold(n)
|
||||
math.randomseed(os.time())
|
||||
__SleepingLinda:receive(.001, randomString(12))
|
||||
end
|
||||
repeat wait() until n()
|
||||
repeat
|
||||
wait()
|
||||
until n()
|
||||
end
|
||||
local rand = math.random(1, 10000000)
|
||||
-- Step 5 Basic Threads!
|
||||
@ -161,9 +174,13 @@ function multi:newSystemThread(name,func,...)
|
||||
end
|
||||
multi.OnSystemThreadDied = multi:newConnection()
|
||||
function multi.InitSystemThreadErrorHandler()
|
||||
if started==true then return end
|
||||
if started == true then
|
||||
return
|
||||
end
|
||||
started = true
|
||||
multi:newThread("ThreadErrorHandler",function()
|
||||
multi:newThread(
|
||||
"ThreadErrorHandler",
|
||||
function()
|
||||
local threads = multi.SystemThreads
|
||||
while true do
|
||||
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||
@ -189,11 +206,16 @@ function multi.InitSystemThreadErrorHandler()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
multi.print("Integrated Lanes!")
|
||||
multi.integration = {} -- for module creators
|
||||
multi.integration.GLOBAL = GLOBAL
|
||||
multi.integration.THREAD = THREAD
|
||||
require("multi.integration.shared")
|
||||
return {init=function() return GLOBAL, THREAD end}
|
||||
return {
|
||||
init = function()
|
||||
return GLOBAL, THREAD
|
||||
end
|
||||
}
|
||||
|
||||
@ -22,6 +22,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
local multi = require("multi.compat.love2d")
|
||||
if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel
|
||||
return {
|
||||
init = function()
|
||||
return multi.integration.GLOBAL, multi.integration.THREAD
|
||||
end
|
||||
}
|
||||
end
|
||||
function multi:canSystemThread()
|
||||
return true
|
||||
end
|
||||
@ -30,7 +37,8 @@ function multi:getPlatform()
|
||||
end
|
||||
multi.integration = {}
|
||||
multi.integration.love2d = {}
|
||||
multi.integration.love2d.ThreadBase=[[
|
||||
multi.integration.love2d.ThreadBase =
|
||||
[[
|
||||
tab={...}
|
||||
__THREADID__=table.remove(tab,1)
|
||||
__THREADNAME__=table.remove(tab,1)
|
||||
@ -201,7 +209,9 @@ multi:mainloop()
|
||||
GLOBAL = {} -- Allow main thread to interact with these objects as well
|
||||
_G.THREAD_ID = 0
|
||||
__proxy__ = {}
|
||||
setmetatable(GLOBAL,{
|
||||
setmetatable(
|
||||
GLOBAL,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return __proxy__[k]
|
||||
end,
|
||||
@ -214,8 +224,9 @@ setmetatable(GLOBAL,{
|
||||
__channels__[i]:push("SYNC " .. type(v) .. " " .. k .. " " .. resolveData(v))
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
}
|
||||
)
|
||||
THREAD = {} -- Allow main thread to interact with these objects as well
|
||||
multi.integration.love2d.mainChannel = love.thread.getChannel("__MainChan__")
|
||||
isMainThread = true
|
||||
@ -232,7 +243,7 @@ function ToStr(val, name, skipnewlines, depth)
|
||||
local tmp = string.rep(" ", depth)
|
||||
if name then
|
||||
if type(name) == "string" then
|
||||
tmp = tmp .. "[\""..name.."\"] = "
|
||||
tmp = tmp .. '["' .. name .. '"] = '
|
||||
else
|
||||
tmp = tmp .. "[" .. (name or "") .. "] = "
|
||||
end
|
||||
@ -252,7 +263,7 @@ function ToStr(val, name, skipnewlines, depth)
|
||||
elseif type(val) == "function" then
|
||||
tmp = tmp .. "loadDump([===[" .. dump(val) .. "]===])"
|
||||
else
|
||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
||||
tmp = tmp .. '"[inserializeable datatype:' .. type(val) .. ']"'
|
||||
end
|
||||
return tmp
|
||||
end
|
||||
@ -297,10 +308,10 @@ function dump(func)
|
||||
return table.concat(code)
|
||||
end
|
||||
local function randomString(n)
|
||||
local str = ''
|
||||
local str = ""
|
||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
for i = 1, n do
|
||||
str = str..''..strings[math.random(1,#strings)]
|
||||
str = str .. "" .. strings[math.random(1, #strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
@ -328,7 +339,11 @@ function multi:newSystemThread(name,func,...) -- the main method
|
||||
end
|
||||
function love.threaderror(thread, errorstr)
|
||||
multi.OnError:Fire(thread, errorstr)
|
||||
livingThreads[thread].OnError:Fire(threads[i],err,"Error in systemThread: '"..livingThreads[thread].name.."' <"..errorstr..">")
|
||||
livingThreads[thread].OnError:Fire(
|
||||
threads[i],
|
||||
err,
|
||||
"Error in systemThread: '" .. livingThreads[thread].name .. "' <" .. errorstr .. ">"
|
||||
)
|
||||
multi.print("Error in systemThread: " .. tostring(thread) .. ": " .. errorstr)
|
||||
end
|
||||
local THREAD = {}
|
||||
@ -339,7 +354,9 @@ function THREAD.get(name)
|
||||
return GLOBAL[name]
|
||||
end
|
||||
function THREAD.waitFor(name)
|
||||
repeat multi:uManager() until GLOBAL[name]
|
||||
repeat
|
||||
multi:uManager()
|
||||
until GLOBAL[name]
|
||||
return GLOBAL[name]
|
||||
end
|
||||
function THREAD.getCores()
|
||||
@ -349,12 +366,16 @@ function THREAD.sleep(n)
|
||||
love.timer.sleep(n)
|
||||
end
|
||||
function THREAD.hold(n)
|
||||
repeat multi:uManager() until n()
|
||||
repeat
|
||||
multi:uManager()
|
||||
until n()
|
||||
end
|
||||
__channels__ = {}
|
||||
multi.integration.GLOBAL = GLOBAL
|
||||
multi.integration.THREAD = THREAD
|
||||
updater=multi:newLoop(function(self)
|
||||
updater =
|
||||
multi:newLoop(
|
||||
function(self)
|
||||
local data = multi.integration.love2d.mainChannel:pop()
|
||||
while data do
|
||||
if type(data) == "string" then
|
||||
@ -384,13 +405,18 @@ updater=multi:newLoop(function(self)
|
||||
end
|
||||
data = multi.integration.love2d.mainChannel:pop()
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
multi.OnSystemThreadDied = multi:newConnection()
|
||||
local started = false
|
||||
function multi.InitSystemThreadErrorHandler()
|
||||
if started==true then return end
|
||||
if started == true then
|
||||
return
|
||||
end
|
||||
started = true
|
||||
multi:newThread("ThreadErrorHandler",function()
|
||||
multi:newThread(
|
||||
"ThreadErrorHandler",
|
||||
function()
|
||||
local threads = multi.SystemThreads
|
||||
while true do
|
||||
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||
@ -412,7 +438,8 @@ function multi.InitSystemThreadErrorHandler()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
require("multi.integration.shared")
|
||||
multi.print("Integrated Love2d!")
|
||||
|
||||
@ -21,21 +21,20 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
-- I DEMAND USAGE FOR LUVIT
|
||||
-- Cannot use discordia without my multitasking library (Which I love more that the luvit platform... then again i'm partial :P)
|
||||
package.path = "?/init.lua;?.lua;" .. package.path
|
||||
local function _INIT(luvitThread, timer)
|
||||
-- lots of this stuff should be able to stay the same
|
||||
function os.getOS()
|
||||
if package.config:sub(1,1)=='\\' then
|
||||
return 'windows'
|
||||
if package.config:sub(1, 1) == "\\" then
|
||||
return "windows"
|
||||
else
|
||||
return 'unix'
|
||||
return "unix"
|
||||
end
|
||||
end
|
||||
-- Step 1 get setup threads on luvit... Sigh how do i even...
|
||||
local multi, thread = require("multi")
|
||||
local multi, thread = require("multi").init()
|
||||
isMainThread = true
|
||||
function multi:canSystemThread()
|
||||
return true
|
||||
@ -46,15 +45,18 @@ local function _INIT(luvitThread,timer)
|
||||
local multi = multi
|
||||
-- Step 2 set up the Global table... is this possible?
|
||||
local GLOBAL = {}
|
||||
setmetatable(GLOBAL,{
|
||||
setmetatable(
|
||||
GLOBAL,
|
||||
{
|
||||
__index = function(t, k)
|
||||
--print("No Global table when using luvit integration!")
|
||||
return nil
|
||||
end,
|
||||
__newindex = function(t, k, v)
|
||||
--print("No Global table when using luvit integration!")
|
||||
end,
|
||||
})
|
||||
end
|
||||
}
|
||||
)
|
||||
local THREAD = {}
|
||||
function THREAD.set(name, val)
|
||||
--print("No Global table when using luvit integration!")
|
||||
@ -63,10 +65,73 @@ local function _INIT(luvitThread,timer)
|
||||
--print("No Global table when using luvit integration!")
|
||||
end
|
||||
local function randomString(n)
|
||||
local str = ''
|
||||
local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}
|
||||
local str = ""
|
||||
local strings = {
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"0",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z"
|
||||
}
|
||||
for i = 1, n do
|
||||
str = str..''..strings[math.random(1,#strings)]
|
||||
str = str .. "" .. strings[math.random(1, #strings)]
|
||||
end
|
||||
return str
|
||||
end
|
||||
@ -96,8 +161,8 @@ local function _INIT(luvitThread,timer)
|
||||
end
|
||||
-- Step 5 Basic Threads!
|
||||
local function entry(path, name, func, ...)
|
||||
local timer = require'timer'
|
||||
local luvitThread = require'thread'
|
||||
local timer = require "timer"
|
||||
local luvitThread = require "thread"
|
||||
package.path = path
|
||||
loadstring(func)(...)
|
||||
end
|
||||
@ -120,9 +185,16 @@ local function _INIT(luvitThread,timer)
|
||||
multi.integration.THREAD = THREAD
|
||||
require("multi.integration.shared")
|
||||
-- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh...
|
||||
local interval = timer.setInterval(1, function ()
|
||||
local interval =
|
||||
timer.setInterval(
|
||||
1,
|
||||
function()
|
||||
multi:uManager()
|
||||
end)
|
||||
end
|
||||
)
|
||||
return multi
|
||||
end
|
||||
return {init=function(threadHandle,timerHandle) local multi = _INIT(threadHandle,timerHandle) return GLOBAL, THREAD end}
|
||||
return {init = function(threadHandle, timerHandle)
|
||||
local multi = _INIT(threadHandle, timerHandle)
|
||||
return GLOBAL, THREAD
|
||||
end}
|
||||
|
||||
@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
local multi, thread = require("multi")
|
||||
local multi, thread = require("multi").init()
|
||||
local net = require("net")
|
||||
local bin = require("bin")
|
||||
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix
|
||||
@ -119,7 +119,9 @@ end
|
||||
-- internal global system
|
||||
local GLOBAL = {}
|
||||
local PROXY = {}
|
||||
setmetatable(GLOBAL,{
|
||||
setmetatable(
|
||||
GLOBAL,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return PROXY[k]
|
||||
end,
|
||||
@ -128,7 +130,8 @@ setmetatable(GLOBAL,{
|
||||
PROXY[k] = v
|
||||
multi.OnGUpdate:Fire(k, packData(v))
|
||||
end
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
-- In case you are unable to use broadcasting this can be used to help connect to nodes
|
||||
function multi:nodeManager(port)
|
||||
@ -140,10 +143,13 @@ function multi:nodeManager(port)
|
||||
server.timeouts = {}
|
||||
server.OnNodeAdded = multi:newConnection()
|
||||
server.OnNodeRemoved = multi:newConnection()
|
||||
server.OnDataRecieved(function(server,data,cid,ip,port)
|
||||
server.OnDataRecieved(
|
||||
function(server, data, cid, ip, port)
|
||||
local cmd = data:sub(1, 1)
|
||||
if cmd == "R" then
|
||||
multi:newThread("Node Client Manager",function(loop)
|
||||
multi:newThread(
|
||||
"Node Client Manager",
|
||||
function(loop)
|
||||
while true do
|
||||
if server.timeouts[cid] == true then
|
||||
server.OnNodeRemoved:Fire(server.nodes[cid])
|
||||
@ -156,23 +162,29 @@ function multi:nodeManager(port)
|
||||
end
|
||||
thread.sleep(1)
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
server.nodes[cid] = data:sub(2, -1)
|
||||
server.OnNodeAdded:Fire(server.nodes[cid])
|
||||
elseif cmd == "G" then
|
||||
server.OnNodeAdded(function(node)
|
||||
server.OnNodeAdded(
|
||||
function(node)
|
||||
server:send(cid, node)
|
||||
end)
|
||||
server.OnNodeRemoved(function(node)
|
||||
end
|
||||
)
|
||||
server.OnNodeRemoved(
|
||||
function(node)
|
||||
server:send(cid, "R" .. node:match("(.-)|"))
|
||||
end)
|
||||
end
|
||||
)
|
||||
for i, v in pairs(server.nodes) do
|
||||
server:send(cid, v)
|
||||
end
|
||||
elseif cmd == "P" then
|
||||
server.timeouts[cid] = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
-- The main driving force of the network manager: Nodes
|
||||
function multi:newNode(settings)
|
||||
@ -183,9 +195,11 @@ function multi:newNode(settings)
|
||||
local name = settings.name or multi.randomString(8)
|
||||
local node = {}
|
||||
node.name = name
|
||||
multi.OnError(function(i,error)
|
||||
multi.OnError(
|
||||
function(i, error)
|
||||
node.OnError:Fire(node, error, node.server)
|
||||
end)
|
||||
end
|
||||
)
|
||||
node.server = net:newUDPServer(0) -- hosts the node using the default port
|
||||
_, node.port = node.server.udp:getsockname()
|
||||
node.connections = net.ClientCache
|
||||
@ -193,7 +207,8 @@ function multi:newNode(settings)
|
||||
node.functions = bin.stream("RegisteredFunctions.dat", false)
|
||||
node.hasFuncs = {}
|
||||
node.OnError = multi:newConnection()
|
||||
node.OnError(function(node,err,master)
|
||||
node.OnError(
|
||||
function(node, err, master)
|
||||
multi.print("ERROR", err, node.name)
|
||||
local temp = bin.new()
|
||||
temp:addBlock(#node.name, 2)
|
||||
@ -204,17 +219,21 @@ function multi:newNode(settings)
|
||||
multi.print(i)
|
||||
v[1]:send(v[2], char(CMD_ERROR) .. temp.data, v[3])
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
if settings.managerDetails then
|
||||
local c = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
||||
if not c then
|
||||
multi.print("Cannot connect to the node manager! Ensuring broadcast is enabled!") settings.noBroadCast = false
|
||||
multi.print("Cannot connect to the node manager! Ensuring broadcast is enabled!")
|
||||
settings.noBroadCast = false
|
||||
else
|
||||
c.OnDataRecieved(function(self,data)
|
||||
c.OnDataRecieved(
|
||||
function(self, data)
|
||||
if data == "ping" then
|
||||
self:send("P")
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
c:send("RNODE_" .. name .. "|" .. net.getLocalIP() .. "|" .. node.port)
|
||||
end
|
||||
end
|
||||
@ -230,7 +249,9 @@ function multi:newNode(settings)
|
||||
len = node.functions:read(1)
|
||||
_G[name] = resolveData(func)
|
||||
node.hasFuncs[name] = true
|
||||
if not len then break end
|
||||
if not len then
|
||||
break
|
||||
end
|
||||
len = byte(len)
|
||||
end
|
||||
end
|
||||
@ -261,7 +282,8 @@ function multi:newNode(settings)
|
||||
end
|
||||
node.loadRate = 1
|
||||
-- Lets tell the network we are alive!
|
||||
node.server.OnDataRecieved(function(server,data,cid,ip,port)
|
||||
node.server.OnDataRecieved(
|
||||
function(server, data, cid, ip, port)
|
||||
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
||||
local dat = data:sub(2, -1) -- the data that you want to read
|
||||
if cmd == CMD_PING then
|
||||
@ -306,25 +328,35 @@ function multi:newNode(settings)
|
||||
elseif cmd == CMD_INITNODE then
|
||||
multi.print("Connected with another node!")
|
||||
node.connections[dat] = {server, ip, port}
|
||||
multi.OnGUpdate(function(k,v)
|
||||
multi.OnGUpdate(
|
||||
function(k, v)
|
||||
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
||||
end)-- set this up
|
||||
end
|
||||
)
|
||||
-- set this up
|
||||
elseif cmd == CMD_INITMASTER then
|
||||
multi.print("Connected to the master!", dat)
|
||||
node.connections[dat] = {server, ip, port}
|
||||
multi.OnGUpdate(function(k,v)
|
||||
multi.OnGUpdate(
|
||||
function(k, v)
|
||||
server:send(ip, table.concat {char(CMD_GLOBAL), k, "|", v}, port)
|
||||
end)-- set this up
|
||||
multi:newTLoop(function()
|
||||
end
|
||||
)
|
||||
-- set this up
|
||||
multi:newTLoop(
|
||||
function()
|
||||
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
||||
end,node.loadRate)
|
||||
end,
|
||||
node.loadRate
|
||||
)
|
||||
server:send(ip, char(CMD_LOAD) .. node.name .. "|" .. multi:getLoad(), port)
|
||||
server:send(ip, char(CMD_INITNODE) .. node.name, port)
|
||||
elseif cmd == CMD_GLOBAL then
|
||||
local k, v = dat:match("(.-)|(.+)")
|
||||
PROXY[k] = resolveData(v)
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
function node:sendTo(name, data)
|
||||
local conn = node.connections[name]
|
||||
conn[1]:send(conn[2], data, conn[3])
|
||||
@ -350,27 +382,34 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
master.connections = net.ClientCache -- Link to the client cache that is created on the net interface
|
||||
master.loads = {}
|
||||
master.timeouts = {}
|
||||
master.trigger = multi:newFunction(function(self,node)
|
||||
master.trigger =
|
||||
multi:newFunction(
|
||||
function(self, node)
|
||||
master.OnFirstNodeConnected:Fire(node)
|
||||
self:Pause()
|
||||
end)
|
||||
end
|
||||
)
|
||||
if settings.managerDetails then
|
||||
local client = net:newTCPClient(settings.managerDetails[1], settings.managerDetails[2])
|
||||
if not client then
|
||||
multi.print("Warning: Cannot connect to the node manager! Ensuring broadcast listening is enabled!") settings.noBroadCast = false
|
||||
multi.print("Warning: Cannot connect to the node manager! Ensuring broadcast listening is enabled!")
|
||||
settings.noBroadCast = false
|
||||
else
|
||||
client.OnDataRecieved(function(client,data)
|
||||
client.OnDataRecieved(
|
||||
function(client, data)
|
||||
local cmd = data:sub(1, 1)
|
||||
if cmd == "N" then
|
||||
print(data)
|
||||
local name, ip, port = data:match("(.-)|(.-)|(.+)")
|
||||
local c = net:newUDPClient(ip, port)
|
||||
net.OnCastedClientInfo:Fire(c,name,ip,port)master.connections[name]=c
|
||||
net.OnCastedClientInfo:Fire(c, name, ip, port)
|
||||
master.connections[name] = c
|
||||
elseif cmd == "R" then
|
||||
local name = data:sub(2, -1)
|
||||
master.connections[name] = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
client:send("G") -- init your connection as a master
|
||||
end
|
||||
end
|
||||
@ -441,12 +480,20 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
name = self:getRandomNode()
|
||||
end
|
||||
if name == nil then
|
||||
multi:newEvent(function() return name~=nil end):OnEvent(function(evnt)
|
||||
multi:newEvent(
|
||||
function()
|
||||
return name ~= nil
|
||||
end
|
||||
):OnEvent(
|
||||
function(evnt)
|
||||
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
||||
evnt:Destroy()
|
||||
end):SetName("DelayedSendTask"):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
|
||||
end
|
||||
):SetName("DelayedSendTask"):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(
|
||||
function(self)
|
||||
self:Destroy()
|
||||
end)
|
||||
end
|
||||
)
|
||||
else
|
||||
self:sendTo(name, char(CMD_TASK) .. len .. aData .. len2 .. fData)
|
||||
end
|
||||
@ -460,12 +507,20 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
name = "NODE_" .. name
|
||||
end
|
||||
if self.connections[name] == nil then
|
||||
multi:newEvent(function() return self.connections[name]~=nil end):OnEvent(function(evnt)
|
||||
multi:newEvent(
|
||||
function()
|
||||
return self.connections[name] ~= nil
|
||||
end
|
||||
):OnEvent(
|
||||
function(evnt)
|
||||
self.connections[name]:send(data)
|
||||
evnt:Destroy()
|
||||
end):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(function(self)
|
||||
end
|
||||
):SetName("DelayedSendTask"):SetTime(8):OnTimedOut(
|
||||
function(self)
|
||||
self:Destroy()
|
||||
end)
|
||||
end
|
||||
)
|
||||
else
|
||||
self.connections[name]:send(data)
|
||||
end
|
||||
@ -489,18 +544,24 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
end
|
||||
return list[math.random(1, #list)]
|
||||
end
|
||||
net.OnCastedClientInfo(function(client,name,ip,port)
|
||||
multi.OnGUpdate(function(k,v)
|
||||
net.OnCastedClientInfo(
|
||||
function(client, name, ip, port)
|
||||
multi.OnGUpdate(
|
||||
function(k, v)
|
||||
client:send(table.concat {char(CMD_GLOBAL), k, "|", v})
|
||||
end)
|
||||
end
|
||||
)
|
||||
local nodename
|
||||
for i, v in pairs(master.connections) do
|
||||
nodename = i
|
||||
end
|
||||
client.OnClientReady(function()
|
||||
client.OnClientReady(
|
||||
function()
|
||||
client:send(char(CMD_INITMASTER) .. master.name) -- Tell the node that you are a master trying to connect
|
||||
if not settings.managerDetails then
|
||||
multi:newThread("Node Data Link Controller",function(loop)
|
||||
multi:newThread(
|
||||
"Node Data Link Controller",
|
||||
function(loop)
|
||||
while true do
|
||||
if master.timeouts[name] == true then
|
||||
master.timeouts[name] = nil
|
||||
@ -512,10 +573,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
end
|
||||
thread.sleep(1)
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
client.name = name
|
||||
client.OnDataRecieved(function(client,data)
|
||||
client.OnDataRecieved(
|
||||
function(client, data)
|
||||
local cmd = byte(data:sub(1, 1)) -- the first byte is the command
|
||||
local dat = data:sub(2, -1) -- the data that you want to read
|
||||
master.trigger(nodename)
|
||||
@ -541,9 +604,12 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
local name, load = dat:match("(.-)|(.+)")
|
||||
master.loads[name] = tonumber(load)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
if not settings.noBroadCast then
|
||||
net:newCastedClients("NODE_(.+)") -- Searches for nodes and connects to them, the master.clients table will contain them by name
|
||||
end
|
||||
@ -551,6 +617,8 @@ function multi:newMaster(settings) -- You will be able to have more than one mas
|
||||
end
|
||||
-- The init function that gets returned
|
||||
multi.print("Integrated Network Parallelism")
|
||||
return {init = function()
|
||||
return {
|
||||
init = function()
|
||||
return GLOBAL
|
||||
end}
|
||||
end
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
multi, thread = require("multi")
|
||||
local multi, thread = require("multi").init()
|
||||
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
|
||||
local c = {} -- where we will store our object
|
||||
c.name = name -- set the name this is important for the love2d side
|
||||
@ -47,7 +47,9 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
|
||||
end
|
||||
function self:pop() -- pop from the channel
|
||||
local v = self.chan:pop()
|
||||
if not v then return end
|
||||
if not v then
|
||||
return
|
||||
end
|
||||
if type(v) == "table" then
|
||||
tab = {}
|
||||
for i, c in pairs(v) do
|
||||
@ -68,7 +70,9 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
|
||||
end
|
||||
function self:peek()
|
||||
local v = self.chan:peek()
|
||||
if not v then return end
|
||||
if not v then
|
||||
return
|
||||
end
|
||||
if type(v) == "table" then
|
||||
tab = {}
|
||||
for i, c in pairs(v) do
|
||||
@ -130,11 +134,14 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
end
|
||||
local conn = {}
|
||||
conn.obj = multi:newConnection()
|
||||
setmetatable(conn,{
|
||||
setmetatable(
|
||||
conn,
|
||||
{
|
||||
__call = function(self, ...)
|
||||
return self:connect(...)
|
||||
end
|
||||
})
|
||||
}
|
||||
)
|
||||
local ID = sThread.getID()
|
||||
local sync = sThread.waitFor(self.name .. "_CONN_SYNC"):init()
|
||||
local fire = sThread.waitFor(self.name .. "_CONN_FIRE"):init()
|
||||
@ -165,14 +172,17 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
break
|
||||
end
|
||||
end
|
||||
if not good then return multi.print("NonExisting Connection!") end
|
||||
if not good then
|
||||
return multi.print("NonExisting Connection!")
|
||||
end
|
||||
fire:push {to, ID, {...}}
|
||||
end
|
||||
-- FIRE {TO,FROM,{ARGS}}
|
||||
local data
|
||||
local clock = os.clock
|
||||
conn.OnConnectionAdded = multi:newConnection()
|
||||
multi:newLoop(function()
|
||||
multi:newLoop(
|
||||
function()
|
||||
data = fire:peek()
|
||||
if type(data) == "table" and data[1] == ID then
|
||||
if data[2] == ID and conn.IgnoreSelf then
|
||||
@ -185,9 +195,11 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
data = sync:peek()
|
||||
if data ~= nil and data[1] == "SYNCA" and data[2] == ID then
|
||||
sync:pop()
|
||||
multi.nextStep(function()
|
||||
multi.nextStep(
|
||||
function()
|
||||
conn.OnConnectionAdded:Fire(data[3])
|
||||
end)
|
||||
end
|
||||
)
|
||||
table.insert(connections, data[3])
|
||||
end
|
||||
if type(data) == "table" and data[1] == "SYNCR" and data[2] == ID then
|
||||
@ -198,17 +210,22 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
end
|
||||
end
|
||||
end
|
||||
end):setName("STConn.syncer")
|
||||
end
|
||||
):setName("STConn.syncer")
|
||||
return conn
|
||||
end
|
||||
local cleanUp = {}
|
||||
multi.OnSystemThreadDied(function(ThreadID)
|
||||
multi.OnSystemThreadDied(
|
||||
function(ThreadID)
|
||||
for i = 1, #syncs do
|
||||
connSync:push {"SYNCR", syncs[i], ThreadID}
|
||||
end
|
||||
cleanUp[ThreadID] = true
|
||||
end)
|
||||
multi:newThread(c.name.." Connection-Handler",function()
|
||||
end
|
||||
)
|
||||
multi:newThread(
|
||||
c.name .. " Connection-Handler",
|
||||
function()
|
||||
local data
|
||||
local clock = os.clock
|
||||
local syncs = {}
|
||||
@ -234,12 +251,15 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
if data ~= nil and cleanUp[data[1]] then
|
||||
local meh = data[1]
|
||||
connFire:pop() -- lets remove dead thread stuff
|
||||
multi:newAlarm(15):OnRing(function(a)
|
||||
multi:newAlarm(15):OnRing(
|
||||
function(a)
|
||||
cleanUp[meh] = nil
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
GLOBAL[c.name] = c
|
||||
return c
|
||||
end
|
||||
@ -252,22 +272,30 @@ function multi:SystemThreadedBenchmark(n)
|
||||
local GLOBAL = multi.integration.GLOBAL
|
||||
local c = {}
|
||||
for i = 1, cores do
|
||||
multi:newSystemThread("STHREAD_BENCH",function(n)
|
||||
multi:newSystemThread(
|
||||
"STHREAD_BENCH",
|
||||
function(n)
|
||||
local multi = require("multi")
|
||||
if multi:getPlatform() == "love2d" then
|
||||
GLOBAL = _G.GLOBAL
|
||||
sThread = _G.sThread
|
||||
end -- we cannot have upvalues... in love2d globals, not locals must be used
|
||||
queue = sThread.waitFor("THREAD_BENCH_QUEUE"):init() -- always wait for when looking for a variable at the start of the thread!
|
||||
multi:benchMark(n):OnBench(function(self,count)
|
||||
multi:benchMark(n):OnBench(
|
||||
function(self, count)
|
||||
queue:push(count)
|
||||
sThread.kill()
|
||||
error("Thread was killed!")
|
||||
end)
|
||||
multi:mainloop()
|
||||
end,n)
|
||||
end
|
||||
multi:newThread("THREAD_BENCH",function()
|
||||
)
|
||||
multi:mainloop()
|
||||
end,
|
||||
n
|
||||
)
|
||||
end
|
||||
multi:newThread(
|
||||
"THREAD_BENCH",
|
||||
function()
|
||||
local count = 0
|
||||
local cc = 0
|
||||
while true do
|
||||
@ -282,7 +310,8 @@ function multi:SystemThreadedBenchmark(n)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
c.OnBench = multi:newConnection()
|
||||
return c
|
||||
end
|
||||
@ -304,7 +333,8 @@ function multi:newSystemThreadedConsole(name)
|
||||
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
||||
else
|
||||
cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSOLE__"):init()
|
||||
multi:newLoop(function()
|
||||
multi:newLoop(
|
||||
function()
|
||||
local data = cc.stream:pop()
|
||||
if data then
|
||||
local dat = table.remove(data, 1)
|
||||
@ -314,7 +344,8 @@ function multi:newSystemThreadedConsole(name)
|
||||
print(unpack(data))
|
||||
end
|
||||
end
|
||||
end):setName("ST.consoleSyncer")
|
||||
end
|
||||
):setName("ST.consoleSyncer")
|
||||
end
|
||||
else
|
||||
cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init()
|
||||
@ -357,14 +388,20 @@ function multi:newSystemThreadedTable(name)
|
||||
cc.conn = sThread.waitFor(self.name .. "_Tabled_Connection"):init()
|
||||
end
|
||||
function cc:waitFor(name)
|
||||
repeat multi:uManager() until tab[name]~=nil
|
||||
repeat
|
||||
multi:uManager()
|
||||
until tab[name] ~= nil
|
||||
return tab[name]
|
||||
end
|
||||
local link = cc
|
||||
cc.conn(function(k,v)
|
||||
cc.conn(
|
||||
function(k, v)
|
||||
link.tab[k] = v
|
||||
end)
|
||||
setmetatable(cc,{
|
||||
end
|
||||
)
|
||||
setmetatable(
|
||||
cc,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return t.tab[k]
|
||||
end,
|
||||
@ -372,7 +409,8 @@ function multi:newSystemThreadedTable(name)
|
||||
t.tab[k] = v
|
||||
t.conn:Fire(k, v)
|
||||
end
|
||||
})
|
||||
}
|
||||
)
|
||||
return cc
|
||||
end
|
||||
GLOBAL[c.name] = c
|
||||
@ -438,7 +476,9 @@ function multi:newSystemThreadedJobQueue(a,b)
|
||||
end
|
||||
end
|
||||
for i = 1, c.numberofcores do
|
||||
multi:newSystemThread(c.name.." Worker Thread #"..i,function(name)
|
||||
multi:newSystemThread(
|
||||
c.name .. " Worker Thread #" .. i,
|
||||
function(name)
|
||||
local multi = require("multi")
|
||||
if love then -- lets make sure we don't reference up-values if using love2d
|
||||
GLOBAL = _G.GLOBAL
|
||||
@ -453,7 +493,8 @@ function multi:newSystemThreadedJobQueue(a,b)
|
||||
local REG = sThread.waitFor("QUEUE_REG_" .. name):init()
|
||||
local DA = sThread.waitFor("QUEUE_DA_" .. name):init()
|
||||
local lastjob = os.clock()
|
||||
multi:newLoop(function()
|
||||
multi:newLoop(
|
||||
function()
|
||||
local job = JQI:pop()
|
||||
local rd = REG:peek()
|
||||
local da = DA:peek()
|
||||
@ -471,10 +512,12 @@ function multi:newSystemThreadedJobQueue(a,b)
|
||||
da[2](multi)
|
||||
da = nil
|
||||
DA:pop()
|
||||
multi:newAlarm(60):OnRing(function(a)
|
||||
multi:newAlarm(60):OnRing(
|
||||
function(a)
|
||||
ids[meh] = nil
|
||||
a:Destroy()
|
||||
end)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
if job then
|
||||
@ -487,24 +530,34 @@ function multi:newSystemThreadedJobQueue(a,b)
|
||||
JD:push({ID, FUNCS:waitFor(_name)(unpack(job))})
|
||||
end
|
||||
end
|
||||
end)
|
||||
multi:newLoop(function()
|
||||
end
|
||||
)
|
||||
multi:newLoop(
|
||||
function()
|
||||
if os.clock() - lastjob > 1 then
|
||||
sThread.sleep(.1)
|
||||
end
|
||||
end)
|
||||
setmetatable(_G,{
|
||||
end
|
||||
)
|
||||
setmetatable(
|
||||
_G,
|
||||
{
|
||||
__index = function(t, k)
|
||||
return FUNCS[k]
|
||||
end
|
||||
})
|
||||
}
|
||||
)
|
||||
if not love then
|
||||
multi:mainloop()
|
||||
end
|
||||
end,c.name)
|
||||
end,
|
||||
c.name
|
||||
)
|
||||
end
|
||||
local clock = os.clock
|
||||
multi:newThread("JQ-"..c.name.." Manager",function()
|
||||
multi:newThread(
|
||||
"JQ-" .. c.name .. " Manager",
|
||||
function()
|
||||
local _count = 0
|
||||
while _count < c.numberofcores do
|
||||
thread.skip()
|
||||
@ -534,7 +587,8 @@ function multi:newSystemThreadedJobQueue(a,b)
|
||||
c.OnJobCompleted:Fire(unpack(dat))
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
return c
|
||||
end
|
||||
function multi:newSystemThreadedExecute(cmd)
|
||||
@ -544,7 +598,9 @@ function multi:newSystemThreadedExecute(cmd)
|
||||
local name = "Execute_Thread" .. multi.randomString(16)
|
||||
c.name = name
|
||||
GLOBAL[name .. "CMD"] = cmd
|
||||
multi:newSystemThread(name,function()
|
||||
multi:newSystemThread(
|
||||
name,
|
||||
function()
|
||||
if love then -- lets make sure we don't reference upvalues if using love2d
|
||||
GLOBAL = _G.GLOBAL
|
||||
sThread = _G.sThread
|
||||
@ -553,15 +609,19 @@ function multi:newSystemThreadedExecute(cmd)
|
||||
cmd = sThread.waitFor(name .. "CMD")
|
||||
local ret = os.execute(cmd)
|
||||
GLOBAL[name .. "R"] = ret
|
||||
end)
|
||||
end
|
||||
)
|
||||
c.OnCMDFinished = multi:newConnection()
|
||||
c.looper=multi:newLoop(function(self)
|
||||
c.looper =
|
||||
multi:newLoop(
|
||||
function(self)
|
||||
local ret = GLOBAL[self.link.name .. "R"]
|
||||
if ret then
|
||||
self.link.OnCMDFinished:Fire(ret)
|
||||
self:Destroy()
|
||||
end
|
||||
end)
|
||||
end
|
||||
)
|
||||
c.looper.link = c
|
||||
return c
|
||||
end
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user