Working on custom prioritySchemes
This commit is contained in:
parent
42149ffab2
commit
189552ac65
22
README.md
22
README.md
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
281
init.lua
281
init.lua
@ -142,18 +142,27 @@ 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
|
||||||
|
local empty_func = function() end
|
||||||
function multi:newConnection(protect,func,kill)
|
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
|
||||||
@ -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
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
function c:Lock()
|
end
|
||||||
lock = self.Fire
|
lock = true
|
||||||
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
|
return self
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
lock = false
|
||||||
|
return self
|
||||||
|
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
|
end
|
||||||
elseif conn.Destroy then
|
|
||||||
conn:Destroy()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function c:Fire(...)
|
|
||||||
for i=1, #call_funcs do
|
|
||||||
call_funcs[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: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
|
||||||
|
else
|
||||||
|
function c:Fire(...)
|
||||||
|
if lock then return end
|
||||||
|
for i=1,#fast do
|
||||||
|
fast[i](...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function c:Connect(func)
|
function c:Connect(func, name)
|
||||||
local th
|
table.insert(fast, func)
|
||||||
if thread.getRunningThread then
|
if name then
|
||||||
th = thread.getRunningThread()
|
fast[name] = func
|
||||||
|
else
|
||||||
|
fast["Conn_"..multi.randomString(12)] = func
|
||||||
end
|
end
|
||||||
if th then
|
|
||||||
local fref = func
|
|
||||||
func = function(...)
|
|
||||||
__CurrentConnectionThread = th
|
|
||||||
fref(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(call_funcs, func)
|
|
||||||
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
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
else
|
self.uManager = uManagerRefP
|
||||||
multi.error("Invalid priority scheme passed!")
|
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
|
end
|
||||||
|
else
|
||||||
|
self.error("Invalid priority scheme selected!")
|
||||||
|
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()
|
|
||||||
148
tests/test.lua
148
tests/test.lua
@ -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()
|
||||||
Loading…
x
Reference in New Issue
Block a user