Working on custom prioritySchemes

This commit is contained in:
Ryan Ward 2023-05-03 23:09:37 -04:00
parent 42149ffab2
commit 189552ac65
5 changed files with 500 additions and 185 deletions

View File

@ -1,6 +1,10 @@
# Multi Version: 16.0.0 Connecting the dots # Multi Version: 16.0.0 - Getting the priorities straight
**Key Changes** **Key Changes**
- Concat connections - Expanded connection logic
- New integration priorityManager
- Tests for threads
- Consistent behavior between the threading integrations
- Bug fixes
Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it! Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and someone will look into it!
@ -16,10 +20,20 @@ Progress is being made in [v16.0.0](https://github.com/rayaman/multi/tree/v16.0.
INSTALLING INSTALLING
---------- ----------
Link to optional dependencies: Link to optional dependencies:
- [lanes](https://github.com/LuaLanes/lanes) - [lanes](https://github.com/LuaLanes/lanes) `luarocks install lanes`
- [chronos](https://github.com/ldrumm/chronos) `luarocks install chronos`
- [love2d](https://love2d.org/) - [love2d](https://love2d.org/)
When using love2d add multi:uManager() or any processor to love.update()
```lua
function love.update(dt)
multi:uManager()
end
```
To install copy the multi folder into your environment and you are good to go</br> To install copy the multi folder into your environment and you are good to go</br>
If you want to use the system threads, then you'll need to install lanes or love2d game engine! If you want to use the system threads, then you'll need to install lanes or love2d game engine!
@ -34,7 +48,7 @@ https://discord.gg/U8UspuA
Planned features/TODO Planned features/TODO
--------------------- ---------------------
- [x] Create test suite (In progress, mostly done) - [x] ~~Create test suite (In progress, mostly done)~~
- [ ] Network Parallelism rework - [ ] Network Parallelism rework
Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md) Usage: [Check out the documentation for more info](https://github.com/rayaman/multi/blob/master/Documentation.md)

View File

@ -1,7 +1,7 @@
# Changelog # Changelog
Table of contents Table of contents
--- ---
[Update 16.0.0 - Connecting the dots](#update-1600---connecting-the-dots)</br> [Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</br>
[Update 15.3.1 - Bug fix](#update-1531---bug-fix)</br> [Update 15.3.1 - Bug fix](#update-1531---bug-fix)</br>
[Update 15.3.0 - A world of connections](#update-1530---a-world-of-connections)</br> [Update 15.3.0 - A world of connections](#update-1530---a-world-of-connections)</br>
[Update 15.2.1 - Bug fix](#update-1521---bug-fix)</br> [Update 15.2.1 - Bug fix](#update-1521---bug-fix)</br>
@ -58,15 +58,30 @@ Table of contents
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br> [Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) [Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
# Update 16.0.0 - Connecting the dots # Update 16.0.0 - Getting the priorities straight
Added Added
--- ---
### New Integration - priorityManager
Allows the user to have multi auto set priorities. Also adds the functionality to create your own runners (multi:mainloop(), multi:umanager()) that you can set using the priority manager. Even if you do not have `chronos` installed these features will still work!
- multi:setCurrentTask() -- Used to set the current processor. Used in custom processors.
- multi:setCurrentProcess() -- Used to set the current processor. It should only be called on a processor object - multi:setCurrentProcess() -- Used to set the current processor. It should only be called on a processor object
- multi.warn(...) -- Sends a warning. - multi.warn(...) -- Sends a warning. Yellow `WARNING`
- multi.error(err) -- When called this function will gracefully kill multi, cleaning things up. - multi.error(err) -- When called this function will gracefully kill multi, cleaning things up. Red `ERROR`
**Note:** If you want to have multi.print, multi.warn and multi.error to work you need to enable them in settings
```lua
multi, thread = require("multi"):init {
print=true,
warn=true,
error=true -- Errors will throw regardless. Setting to true will
-- cause the library to force hard crash itself!
}
```
- THREAD.setENV(table) -- Set a simple table that will be merged into the global namespace - THREAD.setENV(table) -- Set a simple table that will be merged into the global namespace
**Note:** To maintain compatibility between each integration use simple tables. No self references, and string indices only **Note:** To maintain compatibility between each integration use simple tables. No self references, and string indices only.
```lua ```lua
THREAD.setENV({ THREAD.setENV({
shared_function = function() shared_function = function()
@ -204,8 +219,18 @@ Added
Changed Changed
--- ---
- multi errors now internally call `multi.error` instead of `multi.print`
- Actors Act() method now returns true when the main event is fired. Steps/Loops always return true. Nil is returned otherwise.
- Connection:Connect(func, name) Now you can supply a name and name the connection.
- Connection:getConnection(name) This will return the connection function which you can do what you will with it.
- Fast connections are the only connections. Legacy connections have been removed completely. Not much should change on the users end. Perhaps some minor changes.
- conn:Lock(conn) When supplied with a connection reference (What is returned by Connect(func)) it will only lock that connection Reference and not the entire connection. Calling without any arguments will lock the entire connection.
- connUnlock(conn) When supplied with a connection reference it restores that reference and it can be fired again. When no arguments are supplied it unlocks the entire connection.
**Note:** Lock and Unlock when supplied with arguments and not supplied with arguments operate on different objects. If you unlock an entire connection. Individual connection refs will not unlock. The same applies with locking. The entire connection and references are treated differently.
- multi.OnObjectCreated is only called when an object is created in a particular process. Proc.OnObjectCreated is needed to detect when an object is created within a process. - multi.OnObjectCreated is only called when an object is created in a particular process. Proc.OnObjectCreated is needed to detect when an object is created within a process.
- multi.print shows "INFO" before it's message. - multi.print shows "INFO" before it's message. Blue `INFO`
- Connections internals changed, not too much changed on the surface. - Connections internals changed, not too much changed on the surface.
- newConnection(protect, func, kill) - newConnection(protect, func, kill)
- `protect` disables fastmode, but protects the connection - `protect` disables fastmode, but protects the connection
@ -221,8 +246,9 @@ Removed
Fixed Fixed
--- ---
- multi:reallocate(processor, index) has been fixed to work with the current changes of the library.
- Issue with lanes not handling errors properly. This is now resolved - Issue with lanes not handling errors properly. This is now resolved
- Oversight with how pushStatus worked with nesting threaded functions, connections and forwarding events - Oversight with how pushStatus worked with nesting threaded functions, connections and forwarding events. Changes made and this works now!
```lua ```lua
func = thread:newFunction(function() func = thread:newFunction(function()
for i=1,10 do for i=1,10 do

299
init.lua
View File

@ -142,25 +142,34 @@ function multi.ForEach(tab,func)
for i=1,#tab do func(tab[i]) end for i=1,#tab do func(tab[i]) end
end end
function multi.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
local optimization_stats = {} local optimization_stats = {}
local ignoreconn = true local ignoreconn = true
function multi:newConnection(protect, func, kill) local empty_func = function() end
function multi:newConnection(protect,func,kill)
local c={} local c={}
local call_funcs = {} local call_funcs = {}
local lock = false local lock = false
c.__connectionAdded = function() end local locked = {}
c.rawadd = false local fast = {}
c.Parent = self c.Parent=self
setmetatable(c,{ setmetatable(c,{__call=function(self,...)
__call=function(self, ...) -- ()
local t = ... local t = ...
if type(t)=="table" then if type(t)=="table" then
for i,v in pairs(t) do for i,v in pairs(t) do
if v == self then if v==self then
local ref = self:Connect(select(2, ...)) local ref = self:Connect(select(2,...))
if ref then if ref then
ref.root_link = select(1, ...) ref.root_link = select(1,...)
return ref return ref
end end
return self return self
@ -171,49 +180,6 @@ function multi:newConnection(protect, func, kill)
return self:Connect(...) return self:Connect(...)
end end
end, end,
__mod = function(obj1, obj2) -- %
local cn = multi:newConnection()
if type(obj1) == "function" and type(obj2) == "table" then
obj2(function(...)
cn:Fire(obj1(...))
end)
else
multi.error("Invalid mod!", type(obj1), type(obj2),"Expected function, connection(table)")
end
return cn
end,
__concat = function(obj1, obj2) -- ..
local cn = multi:newConnection()
local ref
if type(obj1) == "function" and type(obj2) == "table" then
cn(function(...)
if obj1(...) then
obj2:Fire(...)
end
end)
cn.__connectionAdded = function(conn, func)
cn:Unconnect(conn)
obj2:Connect(func)
end
elseif type(obj1) == "table" and type(obj2) == "function" then
ref = cn(function(...)
obj1:Fire(...)
obj2(...)
end)
cn.__connectionAdded = function()
cn.rawadd = true
cn:Unconnect(ref)
ref = cn(function(...)
if obj2(...) then
obj1:Fire(...)
end
end)
end
else
multi.error("Invalid concat!", type(obj1), type(obj2),"Expected function/connection(table), connection(table)/function")
end
return cn
end,
__add = function(c1,c2) -- Or __add = function(c1,c2) -- Or
local cn = multi:newConnection() local cn = multi:newConnection()
c1(function(...) c1(function(...)
@ -270,63 +236,106 @@ function multi:newConnection(protect, func, kill)
return #call_funcs~=0 return #call_funcs~=0
end end
function c:getConnection(name,ignore) function c:Lock(conn)
if ignore then if conn and not conn.lock then
return connections[name] or CRef conn.lock = function() end
else for i = 1, #fast do
return connections[name] or self if conn.ref == fast[i] then
fast[i] = conn.lock
return self
end
end
return self
end end
end lock = true
function c:Lock()
lock = self.Fire
self.Fire = function() end
return self return self
end end
function c:Unlock() function c:Unlock(conn)
self.Fire = lock if conn and conn.lock then
for i = 1, #fast do
if conn.lock == fast[i] then
fast[i] = conn.ref
return self
end
end
return self
end
lock = false
return self return self
end end
if protect then
function c:Fire(...)
if lock then return end
local kills = {}
for i=1,#fast do
local suc, err = pcall(fast[i], ...)
if not suc then
print(err)
end
if kill then
table.remove(kills,i)
multi:newTask(function()
for _,k in pairs(kills) do
table.remove(fast, k)
end
end)
end
end
end
end
function c:getConnections() function c:getConnections()
return call_funcs return call_funcs
end end
function c:getConnection(name, ignore)
return fast[name] or function() multi:warning("") end
end
function c:Unconnect(conn) function c:Unconnect(conn)
if conn.fast then for i = 1, #fast do
for i = 1, #call_funcs do if conn.ref == fast[i] then
if conn.ref == call_funcs[i] then return table.remove(fast, i), i
table.remove(call_funcs, i) end
end
end
function c:fastMode() return self end
if kill then
local kills = {}
function c:Fire(...)
if lock then return end
for i=1,#fast do
fast[i](...)
if kill then
table.insert(kills,i)
multi:newTask(function()
for k = #kills, 1, -1 do
table.remove(fast, k)
table.remove(kills,i)
end
end)
end end
end end
elseif conn.Destroy then
conn:Destroy()
end end
end else
function c:Fire(...)
function c:Fire(...) if lock then return end
for i=1, #call_funcs do for i=1,#fast do
call_funcs[i](...) fast[i](...)
end
end
-- Not needed anymore, since it's so light, I'll leave it in forever
function c:fastMode() return self end
function c:Connect(func)
local th
if thread.getRunningThread then
th = thread.getRunningThread()
end
if th then
local fref = func
func = function(...)
__CurrentConnectionThread = th
fref(...)
end end
end end
table.insert(call_funcs, func) end
function c:Connect(func, name)
table.insert(fast, func)
if name then
fast[name] = func
else
fast["Conn_"..multi.randomString(12)] = func
end
local temp = {fast = true} local temp = {fast = true}
setmetatable(temp,{ setmetatable(temp,{
__call=function(s,...) __call=function(s,...)
@ -346,11 +355,7 @@ function multi:newConnection(protect, func, kill)
end, end,
}) })
temp.ref = func temp.ref = func
if self.rawadd then temp.name = name
self.rawadd = false
else
self.__connectionAdded(temp, func)
end
return temp return temp
end end
@ -366,41 +371,11 @@ function multi:newConnection(protect, func, kill)
return temp return temp
end end
if find_optimization then
--
end
c.connect=c.Connect c.connect=c.Connect
c.GetConnection=c.getConnection c.GetConnection=c.getConnection
c.HasConnections = c.hasConnections c.HasConnections = c.hasConnections
c.GetConnection = c.getConnection c.GetConnection = c.getConnection
if protect then -- Do some tests and override the fastmode if you want to do something differently
function c:Fire(...)
for i=#call_funcs,1,-1 do
if not call_funcs[i] then return end
local suc, err = pcall(call_funcs[i],...)
if not suc then
multi.print(err)
end
if kill then
table.remove(call_funcs,i)
end
end
end
elseif kill then
function c:Fire(...)
for i=#call_funcs,1,-1 do
call_funcs[i](...)
table.remove(call_funcs,i)
end
end
end
if func then
c = c .. func
end
if not(ignoreconn) then if not(ignoreconn) then
self:create(c) self:create(c)
end end
@ -474,6 +449,7 @@ function multi:SetTime(n)
self.link:Pause() self.link:Pause()
self.OnTimedOut:Fire(self.link) self.OnTimedOut:Fire(self.link)
self:Destroy() self:Destroy()
return true
end end
end end
return self return self
@ -564,7 +540,7 @@ function multi:isDone()
end end
function multi:create(ref) function multi:create(ref)
self.OnObjectCreated:Fire(ref,self) self.OnObjectCreated:Fire(ref, self)
return self return self
end end
@ -653,6 +629,7 @@ function multi:newEvent(task)
self:Pause() self:Pause()
self.returns = t self.returns = t
c.OnEvent:Fire(self) c.OnEvent:Fire(self)
return true
end end
end end
function c:SetTask(func) function c:SetTask(func)
@ -675,6 +652,7 @@ function multi:newUpdater(skip)
if pos >= skip then if pos >= skip then
pos = 0 pos = 0
self.OnUpdate:Fire(self) self.OnUpdate:Fire(self)
return true
end end
pos = pos+1 pos = pos+1
end end
@ -701,6 +679,7 @@ function multi:newAlarm(set)
self.Active=false self.Active=false
self.OnRing:Fire(self) self.OnRing:Fire(self)
t = clock() t = clock()
return true
end end
end end
function c:Resume() function c:Resume()
@ -732,10 +711,12 @@ function multi:newLoop(func,notime)
if notime then if notime then
function c:Act() function c:Act()
self.OnLoop:Fire(self) self.OnLoop:Fire(self)
return true
end end
else else
function c:Act() function c:Act()
self.OnLoop:Fire(self,clock()-start) self.OnLoop:Fire(self,clock()-start)
return true
end end
end end
c.OnLoop = self:newConnection():fastMode() c.OnLoop = self:newConnection():fastMode()
@ -783,6 +764,7 @@ function multi:newStep(start,reset,count,skip)
if self.spos>=self.skip then if self.spos>=self.skip then
self.spos=0 self.spos=0
end end
return true
end end
c.Reset=c.Resume c.Reset=c.Resume
c.OnStart = self:newConnection():fastMode() c.OnStart = self:newConnection():fastMode()
@ -820,6 +802,7 @@ function multi:newTLoop(func,set)
self.life=self.life+1 self.life=self.life+1
self.timer:Reset() self.timer:Reset()
self.OnLoop:Fire(self,self.life) self.OnLoop:Fire(self,self.life)
return true
end end
end end
function c:Set(set) function c:Set(set)
@ -878,6 +861,7 @@ function multi:newTStep(start,reset,count,set)
self.OnEnd:Fire(self) self.OnEnd:Fire(self)
self.pos=self.start self.pos=self.start
end end
return true
end end
end end
function c:Set(set) function c:Set(set)
@ -957,6 +941,14 @@ function multi.getCurrentTask()
return __CurrentTask return __CurrentTask
end end
function multi:setCurrentProcess()
__CurrentProcess = self
end
function multi:setCurrentTask()
__CurrentTask = self
end
function multi:getName() function multi:getName()
return self.Name return self.Name
end end
@ -998,7 +990,7 @@ function multi:newProcessor(name, nothread)
c.OnError = multi:newConnection() c.OnError = multi:newConnection()
end end
c.OnError(multi.print) c.OnError(multi.error)
function c:getThreads() function c:getThreads()
return c.threads return c.threads
@ -1379,7 +1371,7 @@ function thread:newThread(name, func, ...)
c.isError = false c.isError = false
c.OnError = multi:newConnection(true,nil,true) c.OnError = multi:newConnection(true,nil,true)
c.OnDeath = multi:newConnection(true,nil,true) c.OnDeath = multi:newConnection(true,nil,true)
c.OnError(multi.print) c.OnError(multi.error)
function c:getName() function c:getName()
return c.Name return c.Name
@ -1450,7 +1442,7 @@ function thread:newThread(name, func, ...)
globalThreads[c] = multi globalThreads[c] = multi
threadid = threadid + 1 threadid = threadid + 1
self:create(c) multi:getCurrentProcess():create(c)
c.creationTime = os.clock() c.creationTime = os.clock()
return c return c
end end
@ -1865,10 +1857,6 @@ local function doOpt()
end end
end end
function multi:setCurrentProcess()
__CurrentProcess = self
end
local init = false local init = false
function multi.init(settings, realsettings) function multi.init(settings, realsettings)
if settings == multi then settings = realsettings end if settings == multi then settings = realsettings end
@ -2076,15 +2064,6 @@ else
end end
end end
function multi.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 multi:getChildren() function multi:getChildren()
return self.Mainloop return self.Mainloop
end end
@ -2173,12 +2152,16 @@ function multi:IsAnActor()
return self.Act~=nil return self.Act~=nil
end end
function multi:reallocate(o, n) function multi:reallocate(processor, index)
n=n or #o.Mainloop+1 index=index or #processor.Mainloop+1
local int=self.Parent local int=self.Parent
self:Destroy() self.Parent=processor
self.Parent=o print("Moving task to new processor!")
table.insert(o.Mainloop,n,self) if index then
table.insert(processor.Mainloop, index, self)
else
table.insert(processor.Mainloop, self)
end
self.Active=true self.Active=true
return self return self
end end
@ -2200,18 +2183,28 @@ end
function multi.print(...) function multi.print(...)
if multi.defaultSettings.print then if multi.defaultSettings.print then
print("INFO:", table.concat({...}, " ")) local t = {}
for i,v in pairs({...}) do t[#t+1] = tostring(v) end
io.write("\x1b[94mINFO:\x1b[0m " .. table.concat(t," ") .. "\n")
end end
end end
function multi.warn(...) function multi.warn(...)
if multi.defaultSettings.warn then if multi.defaultSettings.warn then
print("WARNING:", table.concat({...}, " ")) local t = {}
for i,v in pairs({...}) do t[#t+1] = tostring(v) end
io.write("\x1b[93mWARNING:\x1b[0m " .. table.concat(t," ") .. "\n")
end end
end end
function multi.error(err) function multi.error(self, err)
error("ERROR: " .. err) if type(err) == "bool" then crash = err end
if type(self) == "string" then err = self end
io.write("\x1b[91mERROR:\x1b[0m " .. err .. "\n")
error("^^^")
if multi.defaultSettings.error then
os.exit(1)
end
end end
multi.GetType = multi.getType multi.GetType = multi.getType

View File

@ -25,57 +25,193 @@ local mainloop_p = multi.mainloop_p
local uManagerRef = multi.uManagerRef local uManagerRef = multi.uManagerRef
local uManagerRefP = multi.uManagerRefP1 local uManagerRefP = multi.uManagerRefP1
local PROFILE_COUNT = 5
-- self:setCurrentProcess() a bit slower than using the local var, but there isn't another option -- self:setCurrentProcess() a bit slower than using the local var, but there isn't another option
local priorityManager = multi:newProcessor("Priority Manager", true) local priorityManager = multi:newProcessor("Priority Manager", true)
priorityManager.newThread = function() multi.warn("You cannot spawn threads on the priority manager!") end
priorityManager.setPriorityScheme = function() multi.warn("You cannot set priority on the priorityManager!") end
local function average(t)
local sum = 0
for _,v in pairs(t) do
sum = sum + v
end
return sum / #t
end
local function getPriority(obj)
local avg = average(obj.__profiling)
if avg < 0.0002 then
multi.print("Setting priority to: core")
return PList[1]
elseif avg < 0.0004 then
multi.print("Setting priority to: very high")
return PList[2]
elseif avg < 0.0008 then
multi.print("Setting priority to: high")
return PList[3]
elseif avg < 0.001 then
multi.print("Setting priority to: above normal")
return PList[4]
elseif avg < 0.0025 then
multi.print("Setting priority to: normal")
return PList[5]
elseif avg < 0.005 then
multi.print("Setting priority to: below normal")
return PList[6]
elseif avg < 0.008 then
multi.print("Setting priority to: low")
return PList[7]
elseif avg < 0.01 then
multi.print("Setting priority to: very low")
return PList[8]
else
multi.print("Setting priority to: idle")
return PList[9]
end
end
local start, stop
priorityManager.uManager = function(self)
-- proc.run already checks if the processor is active
self:setCurrentProcess()
local Loop=self.Mainloop
local ctask
for _D=#Loop,1,-1 do
ctask = Loop[_D]
ctask:setCurrentTask()
start = chronos.nanotime()
if ctask:Act() then
stop = chronos.nanotime()
if ctask.__profiling then
table.insert(ctask.__profiling, stop - start)
end
if ctask.__profiling and #ctask.__profiling == PROFILE_COUNT then
ctask:setPriority(getPriority(ctask))
ctask:reallocate(ctask.__restoreProc)
ctask.__restoreProc = nil
ctask.__profiling = nil
end
end
self:setCurrentProcess()
end
end
local function processHook(obj, proc) local function processHook(obj, proc)
if obj.Type == multi.PROCESS or not(obj.IsAnActor) then return end
obj.__restoreProc = proc obj.__restoreProc = proc
obj.__profiling = {}
obj:reallocate(priorityManager) obj:reallocate(priorityManager)
end end
local function init() local function init()
local RR, PB, TB = 0, 1, 2 local registry = {}
multi.priorityScheme = { multi.priorityScheme = {
RoundRobin = 0, RoundRobin = "RoundRobin",
PriorityBased = 1, PriorityBased = "PriorityBased",
TimedBased = 2 TimeBased = "TimeBased"
} }
function multi:setProfilerCount(count)
PROFILE_COUNT = count
end
function multi:recalibrate()
if self.__processConn then
local items = self.Mainloop
for i,v in pairs(items) do
processHook(v, self)
end
else
multi.error("Cannot recalibrate the priority if not using Time based mangement!")
end
end
function multi:isRegistredScheme(scheme)
--
end
function multi:getRegisteredScheme(scheme)
--
end
local empty_func = function() return true end
function multi:registerScheme(name,options)
local mainloop = options.mainloop or multi.error("You must provide a mainloop option when registring a scheme!")
local umanager = options.umanager or multi.error("You must provide a umanager option when registring a scheme!")
if not options.condition then
multi.warn("You might want to use condition when registring a scheme! A function that returns true has been auto generated for you!")
end
local condition = options.condition or empty_func
if registry[name] and not registry[name].static then
multi.warn("A scheme named: \"" .. name .. "\" has already been registred, overriting!")
else
multi.error("A scheme named: \"" .. name .. "\" has already been registred!")
end
registry[name] = {
mainloop = mainloop,
umanager = umanger,
condition = condition,
static = options.static or false
}
return true
end
function multi:setPriorityScheme(scheme) function multi:setPriorityScheme(scheme)
if not self.Type == multi.PROCESS or not self.Type == multi.ROOTPROCESS then if not self.Type == multi.PROCESS or not self.Type == multi.ROOTPROCESS then
multi.warn("You should only invoke setPriorityScheme on a processor object!") multi.warn("You should only invoke setPriorityScheme on a processor object!")
end end
if scheme == RR then
multi.mainloop = mainloop if scheme == multi.priorityScheme.RoundRobin then
multi.uManager = uManagerRef if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
elseif scheme == PB then self.mainloop = mainloop
multi.mainloop = mainloop_p self.uManager = uManagerRef
multi.uManager = uManagerRefP elseif scheme == multi.priorityScheme.PriorityBased then
elseif scheme == TB then if self.__processConn then self.OnObjectCreated:Unconnect(self.__processConn) self.__processConn = nil end
-- self.mainloop = mainloop_p
self.uManager = uManagerRefP
elseif scheme == multi.priorityScheme.TimeBased then
if not chronos then return multi.warn("Unable to use TimeBased Priority without the chronos library!") end
if self.__processConn then multi.warn("Already enabled TimeBased Priority!") end
self.__processConn = self.OnObjectCreated(processHook)
self.mainloop = mainloop_p
self.uManager = uManagerRefP
elseif self:isRegistredScheme(scheme) then
local mainloop, umanager, condition = self:getRegisteredScheme(scheme)
if condition() then
self.mainloop = mainloop
self.uManager = umanager
end
else else
multi.error("Invalid priority scheme passed!") self.error("Invalid priority scheme selected!")
end end
end end
end end
local function init_chronos() local function init_chronos()
multi:newThread("Priority Manager", function() thread:newThread("System Priority Manager", function()
while true do while true do
thread.yield() thread.yield()
priorityManager.run() priorityManager.run()
end end
end) end).OnError(multi.error)
end end
if chronos then if chronos then
init_chronos() init_chronos()
else else
multi.print("In order to have time based priority management, you need to install the chronos library!") multi.warn("In order to have time based priority management, you need to install the chronos library!")
end end
init() init()
--chronos.nanotime()

View File

@ -1,5 +1,151 @@
package.path = "../?/init.lua;../?.lua;"..package.path package.path = "../?/init.lua;../?.lua;"..package.path
multi, thread = require("multi"):init{print=true,findopt=true} multi, thread = require("multi"):init{print=true,warn=true,error=true}
require("multi.integration.priorityManager") require("multi.integration.priorityManager")
test = multi:newProcessor("Test")
test:setPriorityScheme(multi.priorityScheme.TimeBased)
multi.OnObjectCreated(function(proc, obj)
print("MULTI",proc.Type,obj.Type)
end)
local a = 0
test:newUpdater(100000):OnUpdate(function()
print("Print is slowish")
end)
print("Running...")
multi:mainloop() multi:mainloop()
-- local conn1, conn2, conn3 = multi:newConnection(nil,nil,true), multi:newConnection(), multi:newConnection()
-- local link = conn1(function()
-- print("Conn1, first")
-- end)
-- local link2 = conn1(function()
-- print("Conn1, second")
-- end)
-- local link3 = conn1(function()
-- print("Conn1, third")
-- end)
-- local link4 = conn2(function()
-- print("Conn2, first")
-- end)
-- local link5 = conn2(function()
-- print("Conn2, second")
-- end)
-- local link6 = conn2(function()
-- print("Conn2, third")
-- end)
-- print("Links 1-6",link,link2,link3,link4,link5,link6)
-- conn1:Lock(link)
-- print("All conns\n-------------")
-- conn1:Fire()
-- conn2:Fire()
-- conn1:Unlock(link)
-- conn1:Unconnect(link3)
-- conn2:Unconnect(link6)
-- print("All conns Edit\n---------------------")
-- conn1:Fire()
-- conn2:Fire()
-- thread:newThread(function()
-- print("Awaiting status")
-- thread.hold(conn1 + (conn2 * conn3))
-- print("Conn or Conn2 and Conn3")
-- end)
-- multi:newAlarm(1):OnRing(function()
-- print("Conn")
-- conn1:Fire()
-- end)
-- multi:newAlarm(2):OnRing(function()
-- print("Conn2")
-- conn2:Fire()
-- end)
-- multi:newAlarm(3):OnRing(function()
-- print("Conn3")
-- conn3:Fire()
-- os.exit()
-- end)
-- local conn = multi:newSystemThreadedConnection("conn"):init()
-- multi:newSystemThread("Thread_Test_1", function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:mainloop()
-- end)
-- multi:newSystemThread("Thread_Test_2", function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:newAlarm(2):OnRing(function()
-- console.print("Fire 2!!!")
-- conn:Fire(4,5,6)
-- THREAD.kill()
-- end)
-- multi:mainloop()
-- end)
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print("Mainloop conn got triggered!",a,b,c)
-- end)
-- alarm = multi:newAlarm(1)
-- alarm:OnRing(function()
-- console.print("Fire 1!!!")
-- conn:Fire(1,2,3)
-- end)
-- alarm = multi:newAlarm(3):OnRing(function()
-- multi:newSystemThread("Thread_Test_3",function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local console = THREAD.getConsole()
-- conn(function(a,b,c)
-- console.print(THREAD:getName().." was triggered!",a,b,c)
-- end)
-- multi:newAlarm(4):OnRing(function()
-- console.print("Fire 3!!!")
-- conn:Fire(7,8,9)
-- end)
-- multi:mainloop()
-- end)
-- end)
-- multi:newSystemThread("Thread_Test_4",function()
-- local multi, thread = require("multi"):init()
-- local conn = GLOBAL["conn"]:init()
-- local conn2 = multi:newConnection()
-- local console = THREAD.getConsole()
-- multi:newAlarm(2):OnRing(function()
-- conn2:Fire()
-- end)
-- multi:newThread(function()
-- console.print("Conn Test!")
-- thread.hold(conn + conn2)
-- console.print("It held!")
-- end)
-- multi:mainloop()
-- end)
-- multi:mainloop()