Changelog/Documentation updated. Processors added

This commit is contained in:
Ryan Ward 2021-06-24 23:09:15 -04:00
parent 8c24bcbbb0
commit bdc657771d
4 changed files with 518 additions and 347 deletions

View File

@ -20,6 +20,34 @@ Current Multi Version: 15.0.0
</br>`multi:threadloop([TABLE settings])` — This runs the mainloop by having its own internal while loop running, but prioritizes threads over multi-objects
</br>`multi:uManager([TABLE settings])` — This runs the mainloop, but does not have its own while loop and thus needs to be within a loop of some kind.
# Global Methods
`multi:init()` — Uesd to initiate the library, should only be called once
`multi.getCurrentProcess()` — Returns currently running Process
`multi.`
# Processor Methods
These methods can be called either on the multi namespace or a process returned by `multi:newProcessor()`
`proc.Stop()` — Stops the main process/child process. **Note:** If the main process is stopped all child processes are stopped as well
`proc:getTasksDetails([STRING: displaytype])` — Gets a table or string of all the running tasks
Processor Attributes
---
| Attribute | Type | Returns | Description |
---|---|---|---
Start|Method()|self| Starts the process
Stop|Method()|self| Stops the process
OnError|Connection|connection| Allows connection to the process error handler
Type|Member:`string`|"process"| Contains the type of object
Active|Member:`boolean`|variable| If false the process is not active
Name|Member:`string`|variable| The name set at process creation
process|Thread|thread| A handle to a multi thread object
[Refer to the objects for more methods](#non-actors)
# Multi Settings
**Note:** Most settings have been fined tuned to be at the peak of performance already, however preLoop, protect (Which drastically lowers preformance), and stopOnError should be used freely to fit your needs.

View File

@ -28,11 +28,90 @@ multi:newThread("testing",function()
end).OnError(function(...)
print(...)
end)
sandbox = multi:newProcessor()
sandbox:newTLoop(function()
print("testing...")
end,1)
test2 = multi:newTLoop(function()
print("testing2...")
end,1)
sandbox:newThread("Test Thread",function()
local a = 0
while true do
thread.sleep(1)
a = a + 1
print("Thread Test: ".. multi.getCurrentProcess().Name)
if a == 10 then
sandbox.Stop()
end
end
end).OnError(function(...)
print(...)
end)
multi:newThread("Test Thread",function()
while true do
thread.sleep(1)
print("Thread Test: ".. multi.getCurrentProcess().Name)
end
end).OnError(function(...)
print(...)
end)
sandbox.Start()
multi:mainloop()
```
Added:
---
- N/A
## multi:newProcessor(name)
```lua
package.path = "./?/init.lua;"..package.path
multi,thread = require("multi"):init()
sandbox = multi:newProcessor()
sandbox:newTLoop(function()
print("testing...")
end,1)
sandbox:newThread("Test Thread",function()
local a = 0
while true do
thread.sleep(1)
a = a + 1
print("Thread Test: ".. multi.getCurrentProcess().Name)
if a == 10 then
sandbox.Stop()
end
end
end).OnError(function(...)
print(...)
end)
sandbox.Start() -- Start the process
multi:mainloop()
```
| Attribute | Type | Returns | Description |
---|---|---|---
Start|Method()|self| Starts the process
Stop|Method()|self| Stops the process
OnError|Connection|connection| Allows connection to the process error handler
Type|Member:`string`|"process"| Contains the type of object
Active|Member:`boolean`|variable| If false the process is not active
Name|Member:`string`|variable| The name set at process creation
process|Thread|thread| A handle to a multi thread object
**Note:** All tasks/threads created on a process are linked to that process. If a process is stopped all tasks/threads will be halted until the process is started back up.
Changed:
---

View File

@ -120,7 +120,7 @@ function multi:getTasksDetails(t)
dat2 = dat2.."<SystemThread: "..multi.SystemThreads[i].Name.." | "..os.clock()-multi.SystemThreads[i].creationTime..">\n"
end
end
local load, steps = multi:getLoad()
local load, steps = self:getLoad()
if thread.__threads then
for i=1,#thread.__threads do
dat = dat .. "<THREAD: "..thread.__threads[i].Name.." | "..os.clock()-thread.__threads[i].creationTime..">\n"
@ -130,7 +130,7 @@ function multi:getTasksDetails(t)
return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(load,2).."%\nCycles Per Second Per Task: "..steps.."\n\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: 0\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s..dat2
end
elseif t == "t" or t == "table" then
local load,steps = multi:getLoad()
local load,steps = self:getLoad()
str = {
ProcessName = (self.Name or "Unnamed"),
ThreadCount = #thread.__threads,
@ -206,9 +206,9 @@ end
-- Advance Timer stuff
function multi:SetTime(n)
if not n then n=3 end
local c=multi:newBase()
local c=self:newBase()
c.Type='timemaster'
c.timer=multi:newTimer()
c.timer=self:newTimer()
c.timer:Start()
c.set=n
c.link=self
@ -552,7 +552,7 @@ function multi:newTimer()
time=os.clock()-time
return self
end
self:create(c)
multi:create(c)
return c
end
@ -580,7 +580,7 @@ function multi:newEvent(task)
return self
end
self:setPriority("core")
self:create(c)
multi:create(c)
return c
end
function multi:newUpdater(skip)
@ -602,7 +602,7 @@ function multi:newUpdater(skip)
return self
end
c.OnUpdate=self.OnMainConnect
self:create(c)
multi:create(c)
return c
end
function multi:newAlarm(set)
@ -642,7 +642,7 @@ function multi:newAlarm(set)
self.Parent.Pause(self)
return self
end
self:create(c)
multi:create(c)
return c
end
function multi:newLoop(func)
@ -662,7 +662,7 @@ function multi:newLoop(func)
table.insert(funcs,func)
return self
end
self:create(c)
multi:create(c)
return c
end
function multi:newFunction(func)
@ -688,7 +688,7 @@ function multi:newFunction(func)
return self
end
setmetatable(c,mt)
self:create(c)
multi:create(c)
return c
end
function multi:newStep(start,reset,count,skip)
@ -759,7 +759,7 @@ function multi:newStep(start,reset,count,skip)
self:Resume()
return self
end
self:create(c)
multi:create(c)
return c
end
function multi:newTLoop(func,set)
@ -795,7 +795,7 @@ function multi:newTLoop(func,set)
table.insert(self.func,func)
return self
end
self:create(c)
multi:create(c)
return c
end
function multi:setTimeout(func,t)
@ -869,7 +869,7 @@ function multi:newTStep(start,reset,count,set)
self:Resume()
return self
end
self:create(c)
multi:create(c)
return c
end
local scheduledjobs = {}
@ -902,6 +902,48 @@ function multi:scheduleJob(time,func)
table.insert(scheduledjobs,{time, func,false})
end
local __CurrentProcess = multi
function multi.getCurrentProcess()
return __CurrentProcess
end
local globalThreads = {}
local sandcount = 0
function multi:newProcessor(name)
local c = {}
setmetatable(c,{__index = self})
local multi,thread = require("multi"):init() -- We need to capture the t in thread
local name = name or "Processor_"..sandcount
sandcount = sandcount + 1
c.Mainloop = {}
c.Type = "process"
c.Active = false
c.Name = "multi.process<".. (name or "") .. ">"
c.process = self:newThread(c.Name,function()
while true do
thread.hold(function()
return c.Active
end)
__CurrentProcess = c
c:uManager()
__CurrentProcess = self
end
end)
c.OnError = c.process.OnError
function c.Start()
c.Active = true
return self
end
function c.Stop()
c.Active = false
return self
end
c:attachScheduler()
c.initThreads()
return c
end
-- Threading stuff
local initT = false
local threadCount = 0
@ -917,6 +959,7 @@ function thread.request(t,cmd,...)
thread.requests[t.thread] = {cmd,{...}}
end
function thread.getRunningThread()
local threads = globalThreads
local t = coroutine.running()
if t then
for i,v in pairs(threads) do
@ -1036,7 +1079,7 @@ function multi.hold(func,no)
end
local death = false
if type(func)=="number" then
multi:newThread("Hold_func",function()
self:newThread("Hold_func",function()
thread.sleep(func)
death = true
end)
@ -1045,7 +1088,7 @@ function multi.hold(func,no)
end
else
local rets
multi:newThread("Hold_func",function()
self:newThread("Hold_func",function()
rets = {thread.hold(func)}
death = true
end)
@ -1057,11 +1100,11 @@ function multi.hold(func,no)
end
function multi.holdFor(n,func)
local temp
multi:newThread(function()
multi.getCurrentProcess():newThread(function()
thread.sleep(n)
temp = true
end)
return multi.hold(function()
return multi.getCurrentProcess().hold(function()
if func() then
return func()
elseif temp then
@ -1103,7 +1146,7 @@ function thread:newFunction(func,holdme)
return cleanReturns(rets[1],rets[2],rets[3],rets[4],rets[5],rets[6],rets[7],rets[8],rets[9],rets[10],rets[11],rets[12],rets[13],rets[14],rets[15],rets[16])
end
end
local t = multi:newThread("TempThread",func,...)
local t = multi.getCurrentProcess():newThread("TempThread",func,...)
t.OnDeath(function(self,status,...) rets = {...} end)
t.OnError(function(self,e) err = e end)
if holdme then
@ -1127,8 +1170,11 @@ function multi.setEnv(func,env)
return chunk
end
function multi:newThread(name,func,...)
multi.OnLoad:Fire()
function multi:attachScheduler()
local threads = {}
self.threadsRef = threads
function self:newThread(name,func,...)
self.OnLoad:Fire()
local func = func or name
if type(name) == "function" then
name = "Thread#"..threadCount
@ -1144,12 +1190,12 @@ function multi:newThread(name,func,...)
c.Type="thread"
c.TID = threadid
c.firstRunDone=false
c.timer=multi:newTimer()
c.timer=self:newTimer()
c._isPaused = false
c.returns = {}
c.isError = false
c.OnError = multi:newConnection(true,nil,true)
c.OnDeath = multi:newConnection(true,nil,true)
c.OnError = self:newConnection(true,nil,true)
c.OnDeath = self:newConnection(true,nil,true)
function c:isPaused()
return self._isPaused
end
@ -1203,38 +1249,39 @@ function multi:newThread(name,func,...)
self.Globals=v
end
table.insert(threads,c)
table.insert(globalThreads,c)
if initT==false then
multi.initThreads()
self.initThreads()
end
c.creationTime = os.clock()
threadid = threadid + 1
self:create(c)
multi:create(c)
return c
end
function multi:newISOThread(name,func,_env,...)
multi.OnLoad:Fire()
end
function self:newISOThread(name,func,_env,...)
self.OnLoad:Fire()
local func = func or name
local env = _env or {}
if not env.thread then
env.thread = thread
end
if not env.multi then
env.multi = multi
env.multi = self
end
if type(name) == "function" then
name = "Thread#"..threadCount
end
local func = isolateFunction(func,env)
return self:newThread(name,func)
end
function multi.initThreads(justThreads)
end
function self.initThreads(justThreads)
initT = true
multi.scheduler=multi:newLoop():setName("multi.thread")
multi.scheduler.Type="scheduler"
function multi.scheduler:setStep(n)
self.scheduler=self:newLoop():setName("multi.thread")
self.scheduler.Type="scheduler"
function self.scheduler:setStep(n)
self.skip=tonumber(n) or 24
end
multi.scheduler.skip=0
self.scheduler.skip=0
local t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15
local r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16
local ret,_
@ -1281,7 +1328,7 @@ function multi.initThreads(justThreads)
if type(ret)=="table" then
if ret[1]=="_kill_" then
threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16)
multi.setType(threads[i],multi.DestroyedObj)
self.setType(threads[i],self.DestroyedObj)
table.remove(threads,i)
ret = nil
elseif ret[1]=="_sleep_" then
@ -1329,12 +1376,12 @@ function multi.initThreads(justThreads)
end
CheckRets(i)
end
multi.scheduler:OnLoop(function(self)
self.scheduler:OnLoop(function(self)
for i=#threads,1,-1 do
if threads[i].isError then
if coroutine.status(threads[i].thread)=="dead" then
threads[i].OnError:Fire(threads[i],unpack(threads[i].TempRets))
multi.setType(threads[i],multi.DestroyedObj)
self.setType(threads[i],self.DestroyedObj)
table.remove(threads,i)
end
end
@ -1352,7 +1399,7 @@ function multi.initThreads(justThreads)
if threads[i] and coroutine.status(threads[i].thread)=="dead" then
local t = threads[i].TempRets or {}
threads[i].OnDeath:Fire(threads[i],"ended",t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15],t[16])
multi.setType(threads[i],multi.DestroyedObj)
self.setType(threads[i],self.DestroyedObj)
table.remove(threads,i)
elseif threads[i] and threads[i].task == "skip" then
threads[i].pos = threads[i].pos + 1
@ -1364,7 +1411,7 @@ function multi.initThreads(justThreads)
if clock() - threads[i].intervalR>=threads[i].interval then
t0,t1,t2,t3,t4,t5,t6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16 = threads[i].func()
if t0 then
if t0==multi.NIL then
if t0==self.NIL then
t0 = nil
end
threads[i].task = ""
@ -1420,15 +1467,16 @@ function multi.initThreads(justThreads)
end)
if justThreads then
while true do
multi.scheduler:Act()
self.scheduler:Act()
end
end
end
end
function multi:newService(func) -- Priority managed threads
local c = {}
c.Type = "service"
c.OnStopped = multi:newConnection()
c.OnStarted = multi:newConnection()
c.OnStopped = self:newConnection()
c.OnStarted = self:newConnection()
local Service_Data = {}
local active
local time
@ -1438,7 +1486,7 @@ function multi:newService(func) -- Priority managed threads
local scheme = 1
function c.Start()
if not active then
time = multi:newTimer()
time = self:newTimer()
time:Start()
active = true
c:OnStarted(c,Service_Data)
@ -1453,7 +1501,7 @@ function multi:newService(func) -- Priority managed threads
task(ap)
return c
end
local th = multi:newThread(function()
local th = self:newThread(function()
while true do
process()
end
@ -1537,6 +1585,7 @@ function multi:lightloop(settings)
end
end
function multi:mainloop(settings)
__CurrentProcess = self
multi.OnPreLoad:Fire()
multi.defaultSettings = settings or multi.defaultSettings
self.uManager=self.uManagerRef
@ -1591,8 +1640,10 @@ function multi:mainloop(settings)
self.CID=_D
if not protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1614,8 +1665,10 @@ function multi:mainloop(settings)
self.CID=_D
if not protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1646,8 +1699,10 @@ function multi:mainloop(settings)
self.CID=_D
if not protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1670,6 +1725,7 @@ function multi:mainloop(settings)
if not protect then
if sRef.solid then
sRef:Act()
__CurrentProcess = self
solid = true
else
time = multi.timer(sRef.Act,sRef)
@ -1686,9 +1742,11 @@ function multi:mainloop(settings)
else
if Loop[_D].solid then
Loop[_D]:Act()
__CurrentProcess = self
solid = true
else
time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D])
__CurrentProcess = self
Loop[_D].solid = true
solid = false
end
@ -1728,8 +1786,10 @@ function multi:mainloop(settings)
self.CID=_D
if not protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1748,6 +1808,7 @@ function multi:mainloop(settings)
end
end
function multi:uManager(settings)
__CurrentProcess = self
multi.OnPreLoad:Fire()
multi.defaultSettings = settings or multi.defaultSettings
self.t,self.tt = clock(),0
@ -1786,8 +1847,10 @@ function multi:uManagerRef(settings)
self.CID=_D
if not multi.defaultSettings.protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1809,8 +1872,10 @@ function multi:uManagerRef(settings)
self.CID=_D
if not multi.defaultSettings.protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1837,8 +1902,10 @@ function multi:uManagerRef(settings)
self.CID=_D
if not protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1861,6 +1928,7 @@ function multi:uManagerRef(settings)
if not protect then
if sRef.solid then
sRef:Act()
__CurrentProcess = self
solid = true
else
time = multi.timer(sRef.Act,sRef)
@ -1877,9 +1945,11 @@ function multi:uManagerRef(settings)
else
if Loop[_D].solid then
Loop[_D]:Act()
__CurrentProcess = self
solid = true
else
time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D])
__CurrentProcess = self
Loop[_D].solid = true
solid = false
end
@ -1919,8 +1989,10 @@ function multi:uManagerRef(settings)
self.CID=_D
if not multi.defaultSettings.protect then
Loop[_D]:Act()
__CurrentProcess = self
else
local status, err=pcall(Loop[_D].Act,Loop[_D])
__CurrentProcess = self
if err then
Loop[_D].error=err
self.OnError:Fire(Loop[_D],err)
@ -1987,7 +2059,7 @@ multi.defaultSettings = {
function multi:enableLoadDetection()
if multi.maxSpd then return end
-- here we are going to run a quick benchMark solo
local temp = multi:newProcessor()
local temp = self:newProcessor()
temp:Start()
local t = os.clock()
local stop = false
@ -2006,12 +2078,12 @@ local lastVal = 0
local bb = 0
function multi:getLoad()
if not multi.maxSpd then multi:enableLoadDetection() end
if not multi.maxSpd then self:enableLoadDetection() end
if busy then return lastVal end
local val = nil
if thread.isThread() then
local bench
multi:benchMark(.01):OnBench(function(time,steps)
self:benchMark(.01):OnBench(function(time,steps)
bench = steps
bb = steps
end)
@ -2023,12 +2095,12 @@ function multi:getLoad()
else
busy = true
local bench
multi:benchMark(.01):OnBench(function(time,steps)
self:benchMark(.01):OnBench(function(time,steps)
bench = steps
bb = steps
end)
while not bench do
multi:uManager()
self:uManager()
end
bench = bench^1.5
val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100)
@ -2276,4 +2348,5 @@ else
multi.m.sentinel = newproxy(true)
getmetatable(multi.m.sentinel).__gc = multi.m.onexit
end
multi:attachScheduler()
return multi

View File

@ -21,50 +21,41 @@ end).OnError(function(...)
print(...)
end)
-- local sandcount = 0
-- function multi:newProcessor(name)
-- local c = {}
-- setmetatable(c,{__index = self})
-- local multi,thread = require("multi"):init() -- We need to capture the t in thread
-- local name = name or "Processor_"..sandcount
-- sandcount = sandcount + 1
-- c.Mainloop = {}
-- c.Type = "process"
-- c.Active = false
-- c.OnError = multi:newConnection()
-- c.process = self:newThread(name,function()
-- while true do
-- thread.hold(function()
-- return sandbox.Active
-- end)
-- c:uManager()
-- end
-- end).OnError(c.OnError)
-- function c.Start()
-- c.Active = true
-- end
-- function c.Stop()
-- c.Active = false
-- end
-- return c
-- end
sandbox = multi:newProcessor()
for i,v in pairs(sandbox.process) do
print(i,v)
end
io.read()
sandbox:newTLoop(function()
print("testing...")
end,1)
-- sandbox = multi:newProcessor()
-- sandbox:newTLoop(function()
-- print("testing...")
-- end,1)
test2 = multi:newTLoop(function()
print("testing2...")
end,1)
-- test2 = multi:newTLoop(function()
-- print("testing2...")
-- end,1)
sandbox:newThread("Test Thread",function()
local a = 0
while true do
thread.sleep(1)
a = a + 1
print("Thread Test: ".. multi.getCurrentProcess().Name)
if a == 10 then
sandbox.Stop()
end
end
end).OnError(function(...)
print(...)
end)
multi:newThread("Test Thread",function()
while true do
thread.sleep(1)
print("Thread Test: ".. multi.getCurrentProcess().Name)
end
end).OnError(function(...)
print(...)
end)
-- sandbox:newThread("Test Thread",function()
-- while true do
-- thread.sleep(1)
-- print("Thread Test...")
-- end
-- end)
-- sandbox.Start()
sandbox.Start()
multi:mainloop()