working on 14.0.0

Lots of tweaking
This commit is contained in:
Ryan Ward 2019-11-07 20:21:19 -05:00
parent 689133e71f
commit aa92282b8a
2 changed files with 82 additions and 12 deletions

View File

@ -7,6 +7,11 @@ Added:
- 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!
- 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!
-- tobj.OnDeath(self,status,returns[...]) -- This is a connection that passes a reference to the self, the status, whether or not the thread ended or was killed, and the returns of the thread.
-- tobj.OnError(self,error) -- returns a reference to self and the error as a string
-- **Limitations:** only 7 returns are possible! This was done because creating and destroying table objects are slow. Instead I capture the return values from coroutine.resume into local variables and only allowed it to collect 6 max.
- 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
Fixed: Fixed:
- Connections had a preformance issue where they would create a non function when using connection.getConnection() of a non existing label. - Connections had a preformance issue where they would create a non function when using connection.getConnection() of a non existing label.

View File

@ -28,8 +28,8 @@ local thread = {}
if not _G["$multi"] then if not _G["$multi"] then
_G["$multi"] = {multi=multi,thread=thread} _G["$multi"] = {multi=multi,thread=thread}
end end
multi.Version = "13.1.0" multi.Version = "14.0.0"
multi._VERSION = "13.1.0" multi._VERSION = "14.0.0"
multi.stage = "stable" multi.stage = "stable"
multi.__index = multi multi.__index = multi
multi.Name = "multi.root" multi.Name = "multi.root"
@ -1500,6 +1500,10 @@ function thread.holdFor(sec,n)
thread._Requests() thread._Requests()
return coroutine.yield({"_holdF_", sec, n or function() return true end}) return coroutine.yield({"_holdF_", sec, n or function() return true end})
end end
function thread.holdWithin(skip,n)
thread._Requests()
return coroutine.yield({"_holdW_", skip, n or function() return true end})
end
function thread.skip(n) function thread.skip(n)
thread._Requests() thread._Requests()
if not n then n = 1 elseif n<1 then n = 1 end if not n then n = 1 elseif n<1 then n = 1 end
@ -1529,6 +1533,16 @@ 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 thread.run(func)
local threaddata,t2,t3,t4,t5,t6
local t = multi:newThread("Temp_Thread",func)
t.OnDeath(function(self,status, r1,r2,r3,r4,r5,r6)
threaddata,t2,t3,t4,t5,t6 = r1,r2,r3,r4,r5,r6
end)
return thread.hold(function()
return threaddata,t2,t3,t4,t5,t6
end)
end
function thread.testFor(name,_val,sym) function thread.testFor(name,_val,sym)
thread.hold(function() thread.hold(function()
local val = thread.get(name)~=nil local val = thread.get(name)~=nil
@ -1573,6 +1587,9 @@ function multi:newThread(name,func)
c.firstRunDone=false c.firstRunDone=false
c.timer=multi:newTimer() c.timer=multi:newTimer()
c._isPaused = false c._isPaused = false
c.returns = {}
c.OnError = multi:newConnection()
c.OnDeath = multi:newConnection()
function c:isPaused() function c:isPaused()
return self._isPaused return self._isPaused
end end
@ -1598,7 +1615,6 @@ function multi:newThread(name,func)
c.Destroy = c.Kill c.Destroy = c.Kill
function c.ref:send(name,val) function c.ref:send(name,val)
ret=coroutine.yield({Name=name,Value=val}) ret=coroutine.yield({Name=name,Value=val})
self:syncGlobals(ret)
end end
function c.ref:get(name) function c.ref:get(name)
return self.Globals[name] return self.Globals[name]
@ -1612,11 +1628,9 @@ function multi:newThread(name,func)
function c.ref:sleep(n) function c.ref:sleep(n)
if type(n)=="function" then if type(n)=="function" then
ret=coroutine.yield({"_hold_",n}) ret=coroutine.yield({"_hold_",n})
self:syncGlobals(ret)
elseif type(n)=="number" then elseif type(n)=="number" then
n = tonumber(n) or 0 n = tonumber(n) or 0
ret=coroutine.yield({"_sleep_",n}) ret=coroutine.yield({"_sleep_",n})
self:syncGlobals(ret)
else else
error("Invalid Type for sleep!") error("Invalid Type for sleep!")
end end
@ -1641,11 +1655,14 @@ function multi.initThreads()
end end
multi.scheduler.skip=0 multi.scheduler.skip=0
local t0,t1,t2,t3,t4,t5,t6 local t0,t1,t2,t3,t4,t5,t6
local r1,r2,r3,r4,r5,r6
local ret,_ local ret,_
local function helper(i) local function helper(i)
if ret then if type(ret)=="table" then
if ret[1]=="_kill_" then if ret[1]=="_kill_" then
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6)
table.remove(threads,i) table.remove(threads,i)
ret = nil
elseif ret[1]=="_sleep_" then elseif ret[1]=="_sleep_" then
threads[i].sec = ret[2] threads[i].sec = ret[2]
threads[i].time = clock() threads[i].time = clock()
@ -1670,20 +1687,29 @@ function multi.initThreads()
threads[i].time = clock() threads[i].time = clock()
threads[i].__ready = false threads[i].__ready = false
ret = nil 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 end
end end
multi.scheduler:OnLoop(function(self) multi.scheduler:OnLoop(function(self)
for i=#threads,1,-1 do for i=#threads,1,-1 do
if not threads[i].__started then if not threads[i].__started then
_,ret=coroutine.resume(threads[i].thread) _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread)
threads[i].__started = true threads[i].__started = true
helper(i) helper(i)
end end
if not _ then if not _ then
multi:OnError("Error in thread <"..threads[i].Name..">", ret) threads[i].OnError:Fire(threads[i],ret)
end end
if coroutine.status(threads[i].thread)=="dead" then if coroutine.status(threads[i].thread)=="dead" then
threads[i].OnDeath:Fire(threads[i],"ended",ret,r1,r2,r3,r4,r5,r6)
table.remove(threads,i) table.remove(threads,i)
elseif threads[i].task == "skip" then elseif threads[i].task == "skip" then
threads[i].pos = threads[i].pos + 1 threads[i].pos = threads[i].pos + 1
@ -1713,10 +1739,22 @@ function multi.initThreads()
t0 = nil t0 = nil
t1 = "TIMEOUT" t1 = "TIMEOUT"
end 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 end
if threads[i] and threads[i].__ready then if threads[i] and threads[i].__ready then
threads[i].__ready = false threads[i].__ready = false
_,ret=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6) _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
end end
helper(i) helper(i)
end end
@ -1731,11 +1769,14 @@ function multi:threadloop()
end end
multi.scheduler.skip=0 multi.scheduler.skip=0
local t0,t1,t2,t3,t4,t5,t6 local t0,t1,t2,t3,t4,t5,t6
local r1,r2,r3,r4,r5,r6
local ret,_ local ret,_
local function helper(i) local function helper(i)
if ret then if ret then
if ret[1]=="_kill_" then if ret[1]=="_kill_" then
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6)
table.remove(threads,i) table.remove(threads,i)
ret = nil
elseif ret[1]=="_sleep_" then elseif ret[1]=="_sleep_" then
threads[i].sec = ret[2] threads[i].sec = ret[2]
threads[i].time = clock() threads[i].time = clock()
@ -1760,17 +1801,29 @@ function multi:threadloop()
threads[i].time = clock() threads[i].time = clock()
threads[i].__ready = false threads[i].__ready = false
ret = nil 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 end
end end
while true do while true do
for i=#threads,1,-1 do for i=#threads,1,-1 do
if not threads[i].__started then if not threads[i].__started then
_,ret=coroutine.resume(threads[i].thread) _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread)
threads[i].__started = true threads[i].__started = true
helper(i) helper(i)
end end
if not _ then
threads[i].OnError:Fire(threads[i],ret)
end
if coroutine.status(threads[i].thread)=="dead" then 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) table.remove(threads,i)
elseif threads[i].task == "skip" then elseif threads[i].task == "skip" then
threads[i].pos = threads[i].pos + 1 threads[i].pos = threads[i].pos + 1
@ -1800,10 +1853,22 @@ function multi:threadloop()
t0 = nil t0 = nil
t1 = "TIMEOUT" t1 = "TIMEOUT"
end 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 end
if threads[i].__ready then if threads[i] and threads[i].__ready then
threads[i].__ready = false threads[i].__ready = false
_,ret=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6) _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
end end
helper(i) helper(i)
end end