Reworking the networkManager

some new features
This commit is contained in:
Ryan Ward 2019-12-30 20:16:27 -05:00
parent 71b56023bb
commit 9c74f6c265
22 changed files with 429 additions and 630 deletions

View File

@ -1,10 +1,11 @@
# Changes # Changes
[TOC] [TOC]
Update 14.0.0 Consistency, stability and some new features Update 14.0.0 Consistency, Stability and Additions
------------- -------------
Added: Added:
- multi.init() -- Initlizes the library! Must be called for multiple files to have the same handle. Example below - 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.holdFor(NUMBER sec, FUNCTION condition) -- Works like hold, but timesout when a certain amount of time has passed!
- multi.hold(function or number) -- It's back and uses context switching. Normal multi objs without threading will all be halted where threads will still run. If within a thread continue using thread.hold() and thread.sleep()
- 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 - 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 **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
- thread objects got an addition! - thread objects got an addition!
@ -14,8 +15,8 @@ Added:
- thread.run(function) -- Can only be used within a thread, creates another thread that can do work, but automatically returns whatever from the run function -- Use thread newfunctions for a more powerful version of thread.run() - thread.run(function) -- Can only be used within a thread, creates another thread that can do work, but automatically returns whatever from the run function -- Use thread newfunctions for a more powerful version of thread.run()
- thread:newFunction(FUNCTION; func) - thread:newFunction(FUNCTION; func)
-- returns a function that gives you the option to wait or connect to the returns of the function. -- returns a function that gives you the option to wait or connect to the returns of the function.
-- func().wait() -- only works when within a coroutine based thread -- func().wait() -- waits for the function to return
-- func().connect() -- this can work outside of of a coroutine based thread -- func().connect() -- connects to the function finishing
-- func() -- If your function does not return anything you dont have to use wait or connect at all and the function will return instantly. You could also use wait() to hold until the function does it thing -- func() -- If your function does not return anything you dont have to use wait or connect at all and the function will return instantly. You could also use wait() to hold until the function does it thing
-- If the created function encounters an error, it will return nil, the error message! -- If the created function encounters an error, it will return nil, the error message!
- special variable multi.NIL was added to allow error handling in threaded functions. - special variable multi.NIL was added to allow error handling in threaded functions.
@ -82,12 +83,28 @@ Removed:
- multi:newCustomObject() -- No real use - multi:newCustomObject() -- No real use
Changed: Changed:
- multi connections connect function can now chain connections
```lua
package.path = "./?/init.lua;"..package.path
local multi, thread = require("multi").init()
test = multi:newConnection()
test(function(a)
print("test 1",a.Temp)
a.Temp = "No!"
end,function(a)
print("test 2",a.Temp)
a.Temp = "Maybe!"
end,function(a)
print("test 3",a.Temp)
end)
test:Fire({Temp="Yes!"})
```
- Ties in to the new function that has been added multi.init() - Ties in to the new function that has been added multi.init()
```lua ```lua
local multi, thread = require("multi").init() -- The require multi function still returns the multi object like before local multi, thread = require("multi").init() -- The require multi function still returns the multi object like before
``` ```
- love/lanesManager system threading integration has been reworked. Faster and cleaner code! Consistant code as well - love/lanesManager system threading integration has been reworked. Faster and cleaner code! Consistant code as well
- l
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. 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 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

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -861,9 +861,13 @@ function multi:newConnection(protect,func)
self.func={} self.func={}
return self return self
end end
function c:connect(func,name,num) local function conn_helper(self,func,name,num)
self.ID=self.ID+1 self.ID=self.ID+1
table.insert(self.func,num or #self.func+1,{func,self.ID}) if num then
table.insert(self.func,num,{func,self.ID})
else
table.insert(self.func,1,{func,self.ID})
end
local temp = { local temp = {
Link=self.func, Link=self.func,
func=func, func=func,
@ -908,6 +912,24 @@ function multi:newConnection(protect,func)
end end
return temp return temp
end end
function c:connect(...)--func,name,num
local tab = {...}
local funcs={}
for i=1,#tab do
if type(tab[i])=="function" then
funcs[#funcs+1] = tab[i]
end
end
if #funcs>1 then
local ret = {}
for i=1,#funcs do
table.insert(ret,conn_helper(self,funcs[i]))
end
return ret
else
conn_helper(self,tab[1],tab[2],tab[3])
end
end
c.Connect=c.connect c.Connect=c.connect
c.GetConnection=c.getConnection c.GetConnection=c.getConnection
function c:tofile(path) function c:tofile(path)
@ -1489,11 +1511,34 @@ function thread.waitFor(name)
thread.hold(function() return thread.get(name)~=nil end) thread.hold(function() return thread.get(name)~=nil end)
return thread.get(name) return thread.get(name)
end end
function multi.hold(func)
local death = false
if type(func)=="function" then
local rets
multi:newThread("Hold_func",function()
rets = {thread.hold(func)}
death = true
end)
while not death do
multi.scheduler:Act()
end
return unpack(rets)
elseif type(func)=="number" then
multi:newThread("Hold_func",function()
thread.sleep(func)
death = true
end)
while not death do
multi.scheduler:Act()
end
end
end
function thread:newFunction(func) function thread:newFunction(func)
local c = {Type = "tfunc"} local c = {Type = "tfunc"}
c.__call = function(self,...) c.__call = function(self,...)
local rets, err local rets, err
local function wait() local function wait()
if thread.isThread() then
return thread.hold(function() return thread.hold(function()
if err then if err then
return multi.NIL, err return multi.NIL, err
@ -1501,13 +1546,16 @@ function thread:newFunction(func)
return unpack(rets) return unpack(rets)
end end
end) end)
else
while not rets do
multi.scheduler:Act()
end
return unpack(rets)
end
end end
local t = multi:newThread("TempThread",func,...) local t = multi:newThread("TempThread",func,...)
t.OnDeath(function(self,status,...) rets = {...} end) t.OnDeath(function(self,status,...) rets = {...} end)
t.OnError(function(self,e) err = e end) t.OnError(function(self,e) err = e end)
--if thread.isThread() then
-- return wait()
--else
return { return {
isTFunc = true, isTFunc = true,
wait = wait, wait = wait,
@ -1516,7 +1564,6 @@ function thread:newFunction(func)
t.OnError(function(self,err) f(self, err) end) t.OnError(function(self,err) f(self, err) end)
end end
} }
--end
end end
setmetatable(c,c) setmetatable(c,c)
return c return c
@ -1648,7 +1695,7 @@ function multi:newThread(name,func,...)
threadid = threadid + 1 threadid = threadid + 1
return c return c
end end
function multi.initThreads() function multi.initThreads(justThreads)
initT = true initT = true
multi.scheduler=multi:newLoop():setName("multi.thread") multi.scheduler=multi:newLoop():setName("multi.thread")
multi.scheduler.Type="scheduler" multi.scheduler.Type="scheduler"
@ -1764,120 +1811,14 @@ function multi.initThreads()
helper(i) helper(i)
end end
end) end)
if justThreads then
while true do
multi.scheduler:Act()
end
end
end end
function multi:threadloop() function multi:threadloop()
initT = true multi.initThreads(true)
multi.scheduler=multi:newLoop():setName("multi.thread")
multi.scheduler.Type="scheduler"
function multi.scheduler:setStep(n)
self.skip=tonumber(n) or 24
end
multi.scheduler.skip=0
local t0,t1,t2,t3,t4,t5,t6
local r1,r2,r3,r4,r5,r6
local ret,_
local function helper(i)
if ret then
if ret[1]=="_kill_" then
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6)
table.remove(threads,i)
ret = nil
elseif ret[1]=="_sleep_" then
threads[i].sec = ret[2]
threads[i].time = clock()
threads[i].task = "sleep"
threads[i].__ready = false
ret = nil
elseif ret[1]=="_skip_" then
threads[i].count = ret[2]
threads[i].pos = 0
threads[i].task = "skip"
threads[i].__ready = false
ret = nil
elseif ret[1]=="_hold_" then
threads[i].func = ret[2]
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
elseif ret[1]=="_holdW_" then
threads[i].count = ret[2]
threads[i].pos = 0
threads[i].func = ret[3]
threads[i].task = "holdW"
threads[i].time = clock()
threads[i].__ready = false
ret = nil
end
end
end
while true do
for i=#threads,1,-1 do
if not threads[i].__started then
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread)
threads[i].__started = true
helper(i)
end
if not _ then
threads[i].OnError:Fire(threads[i],ret)
end
if coroutine.status(threads[i].thread)=="dead" then
threads[i].OnDeath(threads[i],"ended",ret,r1,r2,r3,r4,r5,r6)
table.remove(threads,i)
elseif threads[i].task == "skip" then
threads[i].pos = threads[i].pos + 1
if threads[i].count==threads[i].pos then
threads[i].task = ""
threads[i].__ready = true
end
elseif threads[i].task == "hold" then
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
if t0 then
threads[i].task = ""
threads[i].__ready = true
end
elseif threads[i].task == "sleep" then
if clock() - threads[i].time>=threads[i].sec then
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
elseif threads[i].task == "holdW" then
threads[i].pos = threads[i].pos + 1
t0,t1,t2,t3,t4,t5,t6 = threads[i].func()
if t0 then
threads[i].task = ""
threads[i].__ready = true
elseif threads[i].count==threads[i].pos then
threads[i].task = ""
threads[i].__ready = true
t0 = nil
t1 = "TIMEOUT"
end
end
if threads[i] and threads[i].__ready then
threads[i].__ready = false
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
end
helper(i)
end
end
end end
multi.OnError=multi:newConnection() multi.OnError=multi:newConnection()
function multi:newThreadedProcess(name) function multi:newThreadedProcess(name)

View File

@ -1,3 +1,26 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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"):init() local multi, thread = require("multi"):init()
local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD
function multi:newSystemThreadedQueue(name) function multi:newSystemThreadedQueue(name)

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -30,13 +30,6 @@ if multi.integration then -- This allows us to call the lanes manager from suppo
end end
} }
end end
function os.getOS()
if package.config:sub(1, 1) == "\\" then
return "windows"
else
return "unix"
end
end
-- Step 1 get lanes -- Step 1 get lanes
lanes = require("lanes").configure() lanes = require("lanes").configure()
multi.SystemThreads = {} multi.SystemThreads = {}
@ -50,114 +43,11 @@ end
-- Step 2 set up the Linda objects -- Step 2 set up the Linda objects
local __GlobalLinda = lanes.linda() -- handles global stuff local __GlobalLinda = lanes.linda() -- handles global stuff
local __SleepingLinda = lanes.linda() -- handles sleeping stuff local __SleepingLinda = lanes.linda() -- handles sleeping stuff
-- For convenience a GLOBAL table will be constructed to handle requests local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
local GLOBAL = {}
setmetatable(
GLOBAL,
{
__index = function(t, k)
return __GlobalLinda:get(k)
end,
__newindex = function(t, k, v)
__GlobalLinda:set(k, v)
end
}
)
-- Step 3 rewrite the thread methods to use Lindas
local THREAD = {}
function THREAD.set(name, val)
__GlobalLinda:set(name, val)
end
function THREAD.get(name)
__GlobalLinda:get(name)
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"}
for i = 1, n do
str = str .. "" .. strings[math.random(1, #strings)]
end
return str
end
function THREAD.waitFor(name)
local function wait()
math.randomseed(os.time())
__SleepingLinda:receive(.001, randomString(12))
end
repeat
wait()
until __GlobalLinda:get(name)
return __GlobalLinda:get(name)
end
function THREAD.testFor(name, val, sym)
--
end
function THREAD.getCores()
return THREAD.__CORES
end
function THREAD.getThreads()
return GLOBAL.__THREADS__
end
if os.getOS() == "windows" then
THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end
function THREAD.kill() -- trigger the lane destruction
error("Thread was killed!")
end
function THREAD.getName()
return THREAD_NAME
end
function THREAD.getID()
return THREAD_ID
end
_G.THREAD_ID = 0
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]]
function THREAD.sleep(n)
math.randomseed(os.time())
__SleepingLinda:receive(n, randomString(12))
end
function THREAD.hold(n)
local function wait()
math.randomseed(os.time())
__SleepingLinda:receive(.001, randomString(12))
end
repeat
wait()
until n()
end
local rand = math.random(1, 10000000)
-- Step 5 Basic Threads!
local threads = {} local threads = {}
local count = 1 local count = 1
local started = false local started = false
local livingThreads = {} local livingThreads = {}
function multi.removeUpvalues(func)
if not debug then return end
local count=1
local dat = true
while dat do
dat = debug.setupvalue(func, count, nil)
count = count+1
end
end
function multi.getUpvalues(func)
local count=1
local tab = {}
local dat = true
while dat do
dat = debug.getupvalue(func, count)
if dat then
table.insert(tab,dat)
print(dat)
end
count = count+1
end
return tab
end
function multi:newSystemThread(name, func, ...) function multi:newSystemThread(name, func, ...)
multi.InitSystemThreadErrorHandler() multi.InitSystemThreadErrorHandler()
rand = math.random(1, 10000000) rand = math.random(1, 10000000)

View File

@ -1,3 +1,33 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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 function getOS()
if package.config:sub(1, 1) == "\\" then
return "windows"
else
return "unix"
end
end
local function INIT(__GlobalLinda,__SleepingLinda) local function INIT(__GlobalLinda,__SleepingLinda)
local THREAD = {} local THREAD = {}
function THREAD.set(name, val) function THREAD.set(name, val)
@ -16,8 +46,10 @@ local function INIT(__GlobalLinda,__SleepingLinda)
until __GlobalLinda:get(name) until __GlobalLinda:get(name)
return __GlobalLinda:get(name) return __GlobalLinda:get(name)
end end
function THREAD.testFor(name, val, sym) if getOS() == "windows" then
-- THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.getCores() function THREAD.getCores()
return THREAD.__CORES return THREAD.__CORES
@ -59,9 +91,6 @@ local function INIT(__GlobalLinda,__SleepingLinda)
return __GlobalLinda:get(k) return __GlobalLinda:get(k)
end, end,
__newindex = function(t, k, v) __newindex = function(t, k, v)
for i,v in pairs(__GlobalLinda) do
print(i,v)
end
__GlobalLinda:set(k, v) __GlobalLinda:set(k, v)
end end
}) })

View File

@ -1,5 +1,27 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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").init() local multi, thread = require("multi").init()
local status = require("multi.integration.loveManager.status")
local pad = require("multi.integration.loveManager.scratchpad") local pad = require("multi.integration.loveManager.scratchpad")
GLOBAL = multi.integration.GLOBAL GLOBAL = multi.integration.GLOBAL
THREAD = multi.integration.THREAD THREAD = multi.integration.THREAD

View File

@ -1,17 +1,37 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
]]
if ISTHREAD then if ISTHREAD then
error("You cannot require the loveManager from within a thread!") error("You cannot require the loveManager from within a thread!")
end end
local ThreadFileData = [[ local ThreadFileData = [[
ISTHREAD = true ISTHREAD = true
THREAD = require("multi.integration.loveManager.threads") -- order is important! THREAD = require("multi.integration.loveManager.threads") -- order is important!
scratchpad = require("multi.integration.loveManager.scratchpad")
STATUS = require("multi.integration.loveManager.status") STATUS = require("multi.integration.loveManager.status")
__IMPORTS = {...} __IMPORTS = {...}
__FUNC__=table.remove(__IMPORTS,1) __FUNC__=table.remove(__IMPORTS,1)
__THREADID__=table.remove(__IMPORTS,1) __THREADID__=table.remove(__IMPORTS,1)
__THREADNAME__=table.remove(__IMPORTS,1) __THREADNAME__=table.remove(__IMPORTS,1)
pad=table.remove(__IMPORTS,1)
globalhpad=table.remove(__IMPORTS,1)
GLOBAL = THREAD.getGlobal() GLOBAL = THREAD.getGlobal()
multi, thread = require("multi").init() multi, thread = require("multi").init()
THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))]] THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))]]
@ -21,21 +41,16 @@ __THREADID__ = 0
__THREADNAME__ = "MainThread" __THREADNAME__ = "MainThread"
multi.integration={} multi.integration={}
multi.integration.love2d={} multi.integration.love2d={}
multi.integration.love2d.defaultScratchpadSize = 1024
multi.integration.love2d.GlobalScratchpad = love.data.newByteData(string.rep("\0",16*multi.integration.love2d.defaultScratchpadSize))
local THREAD = require("multi.integration.loveManager.threads") local THREAD = require("multi.integration.loveManager.threads")
local scratchpad = require("multi.integration.loveManager.scratchpad")
local STATUS = require("multi.integration.loveManager.status")
local GLOBAL = THREAD.getGlobal() local GLOBAL = THREAD.getGlobal()
local THREAD_ID = 1 -- The Main thread has ID of 0 local THREAD_ID = 1
local OBJECT_ID = 0 local OBJECT_ID = 0
function multi:newSystemThread(name,func,...) function multi:newSystemThread(name,func,...)
local c = {} local c = {}
c.scratchpad = love.data.newByteData(string.rep("\0",multi.integration.love2d.defaultScratchpadSize))
c.name = name c.name = name
c.ID=THREAD_ID c.ID=THREAD_ID
c.thread=love.thread.newThread(ThreadFileData) c.thread=love.thread.newThread(ThreadFileData)
c.thread:start(THREAD.dump(func),c.ID,c.name,c.scratchpad,multi.integration.love2d.GlobalScratchpad,...) c.thread:start(THREAD.dump(func),c.ID,c.name,...)
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread} GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread}
GLOBAL["__THREAD_COUNT"] = THREAD_ID GLOBAL["__THREAD_COUNT"] = THREAD_ID
THREAD_ID=THREAD_ID+1 THREAD_ID=THREAD_ID+1

View File

@ -1,41 +0,0 @@
local ffi = require("ffi")
local scratchpad = {}
local mt = {
__index = function(t, k)
if type(k)=="string" then
local a, b = k:match("(%d+):(%d+)")
return t:read(tonumber(a),tonumber(b))
elseif type(k)=="number" then
return t:read(k,1)
end
end,
__newindex = function(t, k, v)
t:write(v,k)
end
}
function scratchpad:new(data, size, rep)
local c = {}
local pad
if type(data)=="string" then
pad = love.data.newByteData(data or string.rep(rep or "\0",size or 16))
elseif data:type()=="ByteData" then
pad = data
end
local ptr = ffi.cast("unsigned char*",pad:getPointer())
local size = pad:getSize()
function c:write(data, loc, len)
if (loc or 0)+(len or #data)>size then
error("Attpemting to write data outside the bounds of data byte array!")
end
ffi.copy(ptr+(loc or 0), data, len or #data)
end
function c:read(loc, len)
if (((loc or 0)+(len or size)) > size) or ((loc or 0)<0) then
error("Attempt to read outside the bounds of the scratchpad!")
end
return ffi.string(ptr+(loc or 0), len or size)
end
setmetatable(c,mt)
return c
end
return scratchpad

View File

@ -1,13 +0,0 @@
--[[
global pads allow us to directly write data to threads. Each thread has a unique ID which means we can allocate space in memory for each thread to relay stats
Below are codes, If there is more data that needs to be sent we can use byte 0 for that and byte 1,2 and 3 to define a channel
]]
local char = string.char
local cmds = {
OK = char(0x00), -- All is good thread is running can recieve and send data
ERR = char(0x01), -- This tells the system that an error has occured
STOP = char(0x02), -- Thread has finished
BUSY = char(0x03), -- Thread is busy and isn't responding to messages right now
POST = char(0x04), -- Important message for other threads to see, ChannelData with message MSG_TID
}
return cmds

View File

@ -1,5 +1,25 @@
--[[ --[[
Shared methods for both the main thread and MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
]] ]]
require("love.timer") require("love.timer")
require("love.system") require("love.system")
@ -47,7 +67,6 @@ function threads.get(name)
return dat return dat
end end
end end
function threads.waitFor(name) function threads.waitFor(name)
if thread.isThread() then if thread.isThread() then
return thread.hold(function() return thread.hold(function()
@ -63,22 +82,17 @@ function threads.waitFor(name)
end end
return dat return dat
end end
function threads.package(name,val) function threads.package(name,val)
local init = val.init local init = val.init
val.init=threads.dump(val.init) val.init=threads.dump(val.init)
GLOBAL[name]=val GLOBAL[name]=val
val.init=init val.init=init
end end
function threads.testFor(name,val,sym)
-- Not yet implemented
end
function threads.getCores() function threads.getCores()
return love.system.getProcessorCount() return love.system.getProcessorCount()
end end
function threads.kill() function threads.kill()
error("Thread Killed!")
end end
function threads.getThreads() function threads.getThreads()
local t = {} local t = {}

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -21,8 +21,8 @@ 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. 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) -- This module probably will not be maintained any longer!
package.path = "?/init.lua;?.lua;" .. package.path package.path = "?/init.lua;?.lua;" .. package.path
local function _INIT(luvitThread, timer) local function _INIT(luvitThread, timer)
-- lots of this stuff should be able to stay the same -- lots of this stuff should be able to stay the same
@ -66,70 +66,7 @@ local function _INIT(luvitThread, timer)
end end
local function randomString(n) local function randomString(n)
local str = "" local str = ""
local strings = { 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"}
"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 for i = 1, n do
str = str .. "" .. strings[math.random(1, #strings)] str = str .. "" .. strings[math.random(1, #strings)]
end end

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
local multi, thread = require("multi").init() local multi, thread = require("multi"):init()
local net = require("net") local net = require("net")
local bin = require("bin") local bin = require("bin")
bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix bin.setBitsInterface(infinabits) -- the bits interface does not work so well, another bug to fix

View File

@ -0,0 +1,15 @@
local cmds = {
ERROR = 0x00,
PING = 0x01,
PONG = 0x02,
QUEUE = 0x03,
TASK = 0x04,
INITNODE = 0x05,
INITMASTER = 0x06,
GLOBAL = 0x07,
LOAD = 0x08,
CALL = 0x09,
REG = 0x0A,
CONSOLE = 0x0B,
}
return cmds

View File

@ -0,0 +1,23 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
]]

View File

@ -0,0 +1,57 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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"):init()
local net = require("net")
local bin = require("bin")
local char = string.char
local byte = string.byte
bin.setBitsInterface(infinabits)
--[[
--[=[ Pre reqs:
- Network contains nodes
- Network can broadcast/has nodemanager/ is simple and can be scanned
Outline:
- multi:newMasterNode(connectionDetails)
-- master:setDefaultNode(nodeName) -- Set default node
-- master:newNetworkThread(nodeName,func,...) -- Thread is ran on a random node or the default one if set if nodeName is set to nil
-- master:newNetworkChannel(nodeName)
-- master:sendTo(nodeName,data)
- multi:newNode(connectionDetails)
- multi:newNodeManager(connectionDetails) -- This will be incharge of a lot of data handling
]=]
local nGLOBAL, nTHREAD = require("multi.integration.networkManager"):init()
local master = multi:newMasterNode()
master:newNetworkThread("simpleNode",function(a,b,c)
print(a,b,c)
end,1,2,3)
]]
-- The init file should provide the structure that all the other modules build off of
return {
init = function()
--
end
}

View File

@ -0,0 +1,70 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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"):init()
local cmd = require("multi.integration.networkManager.cmds")
local net = require("net")
local bin = require("bin")
local master = {}
master.__index = master
function multi:newMasterNode(connectionDetails)
local c = {}
c.OnDataRecieved = multi:newConnection()
c.defaultNode = ""
c.nodes = {}
if connectionDetails then
-- We do what we do
else
-- Lets make assumptions
end
setmetatable(c, master)
return c
end
function master:setDefaultNode(nodeName)
-- Verify Node is active
if self:nodeExists(nodeName) then
self.defaultNode = nodeName
end
end
function master:newNetworkThread(nodeName,func)
--
end
function master:newNetworkChannel(nodeName)
--
end
function master:sendTo(nodeName,data)
if self:nodeExists(nodeName):wait() then
print("It exists!")
end
end
master.nodeExists = thread:newFunction(function(self,nodeName)
if self.nodes[nodeName] then
local wait = nodes[nodeName]:ping()
local bool = thread.hold(function()
return wait()
end)
return bool
else
return false
end
end)

View File

@ -0,0 +1,23 @@
--[[
MIT License
Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
]]

View File

@ -0,0 +1,4 @@
local bin = require("bin")
local utils = {}
-- Will contain data that handles sterilizing and managing data
return utils

View File

@ -1,7 +1,7 @@
--[[ --[[
MIT License MIT License
Copyright (c) 2019 Ryan Ward Copyright (c) 2020 Ryan Ward
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -167,7 +167,6 @@ function multi:newSystemThreadedConnection(name, protect)
GLOBAL[c.name] = c GLOBAL[c.name] = c
return c return c
end end
function multi:SystemThreadedBenchmark(n) function multi:SystemThreadedBenchmark(n)
n = n or 1 n = n or 1
local cores = multi.integration.THREAD.getCores() local cores = multi.integration.THREAD.getCores()
@ -269,232 +268,6 @@ function multi:newSystemThreadedConsole(name)
GLOBAL[c.name] = c GLOBAL[c.name] = c
return c return c
end end
-- NEEDS WORK
function multi:newSystemThreadedTable(name)
local c = {}
c.name = name -- set the name this is important for identifying what is what
local sThread = multi.integration.THREAD
local GLOBAL = multi.integration.GLOBAL
function c:init() -- create an init function so we can mimic on both love2d and lanes
_G.__Needs_Multi = true
local multi = require("multi")
if multi:getPlatform() == "love2d" then
GLOBAL = _G.GLOBAL
sThread = _G.sThread
end
local cc = {}
cc.tab = {}
if multi.isMainThread then
if not GLOBAL[self.name .. "_Tabled_Connection"] then
cc.conn = multi:newSystemThreadedConnection(self.name .. "_Tabled_Connection"):init()
end
else
cc.conn = sThread.waitFor(self.name .. "_Tabled_Connection"):init()
end
function cc:waitFor(name)
repeat
multi:uManager()
until tab[name] ~= nil
return tab[name]
end
local link = cc
cc.conn(
function(k, v)
link.tab[k] = v
end
)
setmetatable(
cc,
{
__index = function(t, k)
return t.tab[k]
end,
__newindex = function(t, k, v)
t.tab[k] = v
t.conn:Fire(k, v)
end
}
)
return cc
end
GLOBAL[c.name] = c
return c
end
local jobqueuecount = 0
local jqueues = {}
function multi:newSystemThreadedJobQueue(a, b)
jobqueuecount = jobqueuecount + 1
local GLOBAL = multi.integration.GLOBAL
local sThread = multi.integration.THREAD
local c = {}
c.numberofcores = 4
c.idle = nil
c.name = "SYSTEM_THREADED_JOBQUEUE_" .. jobqueuecount
-- This is done to keep backwards compatibility for older code
if type(a) == "string" and not (b) then
c.name = a
elseif type(a) == "number" and not (b) then
c.numberofcores = a
elseif type(a) == "string" and type(b) == "number" then
c.name = a
c.numberofcores = b
elseif type(a) == "number" and type(b) == "string" then
c.name = b
c.numberofcores = a
end
if jqueues[c.name] then
error("A job queue by the name: " .. c.name .. " already exists!")
end
jqueues[c.name] = true
c.isReady = false
c.jobnum = 1
c.OnJobCompleted = multi:newConnection()
local queueIN = self:newSystemThreadedQueue("QUEUE_IN_" .. c.name):init()
local queueCC = self:newSystemThreadedQueue("QUEUE_CC_" .. c.name):init()
local queueREG = self:newSystemThreadedQueue("QUEUE_REG_" .. c.name):init()
local queueJD = self:newSystemThreadedQueue("QUEUE_JD_" .. c.name):init()
local queueDA = self:newSystemThreadedQueue("QUEUE_DA_" .. c.name):init()
c.OnReady = multi:newConnection()
function c:registerJob(name, func)
for i = 1, self.numberofcores do
queueREG:push({name, func})
end
end
c.tempQueue = {}
function c:pushJob(name, ...)
c.idle = os.clock()
if not self.isReady then
table.insert(c.tempQueue, {self.jobnum, name, ...})
self.jobnum = self.jobnum + 1
return self.jobnum - 1
else
queueIN:push {self.jobnum, name, ...}
self.jobnum = self.jobnum + 1
return self.jobnum - 1
end
end
function c:doToAll(func)
local r = multi.randomString(12)
for i = 1, self.numberofcores do
queueDA:push {r, func}
end
end
for i = 1, c.numberofcores do
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
sThread = _G.sThread
end
local CC = sThread.waitFor("QUEUE_CC_" .. name):init()
CC:push("ready")
local FUNCS = {}
local ids = {}
local JQI = sThread.waitFor("QUEUE_IN_" .. name):init()
local JD = sThread.waitFor("QUEUE_JD_" .. name):init()
local REG = sThread.waitFor("QUEUE_REG_" .. name):init()
local DA = sThread.waitFor("QUEUE_DA_" .. name):init()
local lastjob = os.clock()
multi:newLoop(
function()
local job = JQI:pop()
local rd = REG:peek()
local da = DA:peek()
if rd then
if not FUNCS[rd[1]] then
FUNCS[rd[1]] = rd[2]
rd = nil
REG:pop()
end
end
if da then
if not ids[da[1]] then
local meh = da[1]
ids[da[1]] = true
da[2](multi)
da = nil
DA:pop()
multi:newAlarm(60):OnRing(
function(a)
ids[meh] = nil
a:Destroy()
end
)
end
end
if job then
lastjob = os.clock()
local ID = table.remove(job, 1) -- return and remove
local _name = table.remove(job, 1) -- return and remove
if FUNCS[_name] then
JD:push({ID, FUNCS[_name](unpack(job))})
else -- making use of that new holding feature
JD:push({ID, FUNCS:waitFor(_name)(unpack(job))})
end
end
end
)
multi:newLoop(
function()
if os.clock() - lastjob > 1 then
sThread.sleep(.1)
end
end
)
setmetatable(
_G,
{
__index = function(t, k)
return FUNCS[k]
end
}
)
if not love then
multi:mainloop()
end
end,
c.name
)
end
local clock = os.clock
multi:newThread(
"JQ-" .. c.name .. " Manager",
function()
local _count = 0
while _count < c.numberofcores do
thread.skip()
if queueCC:pop() then
_count = _count + 1
end
end
c.isReady = true
for i = 1, #c.tempQueue do
queueIN:push(c.tempQueue[i])
end
c.tempQueue = nil
c.OnReady:Fire(c)
local dat
while true do
if not c.idle then
thread.sleep(.5)
else
if clock() - c.idle >= 15 then
c.idle = nil
end
thread.skip()
end
dat = queueJD:pop()
if dat then
c.idle = clock()
c.OnJobCompleted:Fire(unpack(dat))
end
end
end
)
return c
end
function multi:newSystemThreadedExecute(cmd) function multi:newSystemThreadedExecute(cmd)
local c = {} local c = {}
local GLOBAL = multi.integration.GLOBAL -- set up locals incase we are using lanes local GLOBAL = multi.integration.GLOBAL -- set up locals incase we are using lanes