1.9.2 is out!

Added, updated, and fixed stuff
This commit is contained in:
Ryan Ward 2018-05-17 01:19:56 -04:00
parent 509086295c
commit e32720b687
11 changed files with 556 additions and 171 deletions

19
PManager.txt Normal file
View File

@ -0,0 +1,19 @@
C: 2731526 ~I*7
H: 2341308 ~I*6
A: 1951090 ~I*5
N: 1560872 ~I*4
B: 1170655 ~I*3
L: 780438 ~I*2
I: 390219 ~I
~n=I*PRank
P2
---------------
C: 6700821
H: 1675205
A: 418801
N: 104700
B: 26175
L: 6543
I: 1635
~n=n*4

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,7 @@
# multi Version: 1.9.1 (New Integration! luvit) # multi Version: 1.9.2 (Yes I am alive, and some tweaks and additions have been made)
**NOTE: I have been studying a lot about threading in the past few weeks and have some awesome additions in store! They will take a while to come out though. The goal of the library is still to provide a simple and efficient way to multi task in lua** **NOTE: I have been studying a lot about threading in the past few weeks and have some awesome additions in store! They will take a while to come out though. The goal of the library is still to provide a simple and efficient way to multi task in lua**
**Upcoming Plans:** Adding network support for threading. Kinda like your own lua cloud. This will require the bin, net, and multi library. Once that happens I will include those libraries as a set. This also means that you can expect both a stand alone and joined versions of the libraries.
In Changes you'll find documentation for(In Order): In Changes you'll find documentation for(In Order):
- Sterilizing Objects - Sterilizing Objects
- System Threaded Job Queues - System Threaded Job Queues
@ -35,6 +33,8 @@ Discord
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries. Also you can request features and stuff there as well.</br> For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries. Also you can request features and stuff there as well.</br>
https://discord.gg/U8UspuA</br> https://discord.gg/U8UspuA</br>
**Upcoming Plans:** Adding network support for threading. Kinda like your own lua cloud. This will require the bin, net, and multi library. Once that happens I will include those libraries as a set. This also means that you can expect both a stand alone and joined versions of the libraries.
Planned features/TODO Planned features/TODO
--------------------- ---------------------
- [x] ~~Add system threads for love2d that works like the lanesManager (loveManager, slight differences).~~ - [x] ~~Add system threads for love2d that works like the lanesManager (loveManager, slight differences).~~
@ -813,20 +813,48 @@ We did it! 1 2 3</br>
Changes Changes
------- -------
Update: 1.9.1 Update: 1.9.2
-------------
Added: Added:
Integration "multi.integration.luvitManager" - (THREAD).kill() kills a thread. Note: THREAD is based on what you name it
Limited... Only the basic multi:newSystemThread(...) will work - newTimeStamper() Part of the persistant systems... Useful for when you are running this library for a massive amount of time... like years stright!
Not even data passing will work other than arguments... If using the bin library you can pass tables and function... Even full objects as long as inner recursion is not preasent. Allows one to hook to timed events such as whenever the clock strikes midnight or when the day turns to monday. The event is only done once though. so as soon as monday is set it would trigger then not trigger again until next monday
works for seconds, minutes, days, months, year.
```lua
stamper = multi:newTimeStamper()
stamper:OnTime(int hour,int minute,int second,func) or stamper:OnTime(string time,func) time as 00:00:00
stamper:OnHour(int hour,func)
stamper:OnMinute(int minute,func)
stamper:OnSecond(int second,func)
stamper:OnDay(int day,func) or stamper:OnDay(string day,func) Mon, Tues, Wed, etc...
stamper:OnMonth(int month,func)
stamper:OnYear(int year,func)
```
Updated:
- LoadBalancing, well bettwr load balancing than existed before. This one allowd for multiple processes to have their own load reading. Calling this on the multi object will return the total load for the entire multi enviroment... loads of other processes are indeed affected by what other processes are doing. However if you combine prorioty to the mix of things then you will get differing results... these results however will most likely be higher than normal... different pirorities will have different default thresholds of performence.
Fixed:
- Thread.getName() should now work on lanes and love2d, haven't tested ut nuch with the luvit side of things...
- A bug with the lovemanager table.remove arguments were backwards haha
- The queue object in the love2d threading has been fixed! It now supports sending all objects (even functions as long as no upvalues are present!)
Changed:
- SystemThreadedJobQueues now have built in load management so they are not constantly at 100% cpu usage.
- SystemThreadedJobQueues pushJob now retunts an id of that job which will match the same one that OnJobCompleted returns
Update: 1.9.1
-------------
Added:
- Integration "multi.integration.luvitManager"
- Limited... Only the basic multi:newSystemThread(...) will work
- Not even data passing will work other than arguments... If using the bin library you can pass tables and function... Even full objects as long as inner recursion is not preasent.
Updated: Updated:
multi:newSystemThread(name,func,...) - multi:newSystemThread(name,func,...)
- It will not pass the ... to the func(). Do not know why this wasn't done in the first place :P
- Also multi:getPlatform(will now return "luvit" if using luvit... Though Idk if module creators would use the multi library when inside the luvit enviroment
It will not pass the ... to the func()
Do not know why this wasn't done in the first place :P
Also multi:getPlatform(will now return "luvit" if using luvit... Though Idk if module creators would use the multi library when inside the luvit enviroment
Update: 1.9.0 Update: 1.9.0
------------- -------------
Added: Added:

View File

@ -32,7 +32,7 @@ multi:newThread("test0",function()
end end
end end
end) end)
GLOBAL["BENCH"]=10 GLOBAL["BENCH"]=1
print("Platform is: ",multi:getPlatform()) -- returns love2d or lanes depending on which platform you are using... If I add more intergrations then this method will be updated! corona sdk may see this library in the future... print("Platform is: ",multi:getPlatform()) -- returns love2d or lanes depending on which platform you are using... If I add more intergrations then this method will be updated! corona sdk may see this library in the future...
multi:mainloop() multi:mainloop()
--[[ Output on my machine! I am using luajit and have 6 cores on my computer. Your numbers will vary, but it should look something like this --[[ Output on my machine! I am using luajit and have 6 cores on my computer. Your numbers will vary, but it should look something like this

View File

@ -1,4 +1,4 @@
package.path="?/init.lua;"..package.path --~ package.path="?/init.lua;"..package.path
local GLOBAL,sThread=require("multi.integration.lanesManager").init() local GLOBAL,sThread=require("multi.integration.lanesManager").init()
jQueue=multi:newSystemThreadedJobQueue(n) jQueue=multi:newSystemThreadedJobQueue(n)
jQueue:registerJob("TEST_JOB",function(a,s) jQueue:registerJob("TEST_JOB",function(a,s)
@ -11,7 +11,7 @@ jQueue:registerJob("TEST_JOB2",function()
end) end)
jQueue:start() jQueue:start()
jQueue:doToAll(function() jQueue:doToAll(function()
print("Doing this 6? times!") print("Doing this 16? times!")
end) end)
for i=1,10 do -- Job Name of registered function, ... varargs for i=1,10 do -- Job Name of registered function, ... varargs
jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000)) jQueue:pushJob("TEST_JOB","This is a test!",math.random(1,1000000))

View File

@ -22,6 +22,62 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] ]]
require("bin") require("bin")
multi = {}
multi.Version = "1.9.2"
multi._VERSION = "1.9.2"
multi.stage = "mostly-stable"
multi.__index = multi
multi.Mainloop = {}
multi.Tasks = {}
multi.Tasks2 = {}
multi.Garbage = {}
multi.ender = {}
multi.Children = {}
multi.Paused = {}
multi.Active = true
multi.fps = 60
multi.Id = -1
multi.Type = "mainprocess"
multi.Rest = 0
multi._type = type
multi.Jobs = {}
multi.queue = {}
multi.jobUS = 2
multi.clock = os.clock
multi.time = os.time
multi.LinkedPath = multi
multi.isRunning = false
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
multi.Priority_Core = 1
multi.Priority_High = 4
multi.Priority_Above_Normal = 16
multi.Priority_Normal = 64
multi.Priority_Below_Normal = 256
multi.Priority_Low = 1024
multi.Priority_Idle = 4096
multi.PStep = 1
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
--^^^^
multi.PriorityTick=1 -- Between 1, 2 and 4
multi.Priority=multi.Priority_Core
multi.threshold=256
multi.threstimed=.001
function multi.queuefinal(self)
self:Destroy()
if self.Parent.Mainloop[#self.Parent.Mainloop] then
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
else
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
end
else
for i=1,#self.Parent.funcE do
self.Parent.funcE[i](self)
end
self.Parent:Remove()
end
end
if table.unpack then if table.unpack then
unpack=table.unpack unpack=table.unpack
end end
@ -45,83 +101,19 @@ function print(...)
_print(...) _print(...)
end end
end end
multi = {} _write=io.write
multi.Version="1.9.1" function io.write(...)
multi._VERSION="1.9.1" if not __SUPPRESSWRITES then
multi.stage='mostly-stable' _write(...)
multi.__index = multi
multi.Mainloop={}
multi.Tasks={}
multi.Tasks2={}
multi.Garbage={}
multi.ender={}
multi.Children={}
multi.Paused={}
multi.Active=true
multi.fps=60
multi.Id=-1
multi.Type='mainprocess'
multi.Rest=0
multi._type=type
multi.Jobs={}
multi.queue={}
multi.jobUS=2
multi.clock=os.clock
multi.time=os.time
multi.LinkedPath=multi
multi.isRunning=false
multi.queuefinal=function(self)
self:Destroy()
if self.Parent.Mainloop[#self.Parent.Mainloop] then
if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then
self.Parent.Mainloop[#self.Parent.Mainloop]:Reset()
self.Parent.Mainloop[#self.Parent.Mainloop].Active=true
else
self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
end
else
for i=1,#self.Parent.funcE do
self.Parent.funcE[i](self)
end
self.Parent:Remove()
end end
end end
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2())
multi.Priority_Core=1
multi.Priority_High=4
multi.Priority_Above_Normal=16
multi.Priority_Normal=64
multi.Priority_Below_Normal=256
multi.Priority_Low=1024
multi.Priority_Idle=4096
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
multi.PStep=1
--^^^^
multi.PriorityTick=1 -- Between 1,2 and 4
multi.Priority=multi.Priority_Core
multi.threshold=256
multi.threstimed=.001
function multi:setThreshold(n)
self.threshold=n or 120
end
function multi:setThrestimed(n) function multi:setThrestimed(n)
self.threstimed=n or .001 self.deltaTarget=n or .1
end end
function multi:getLoad() function multi:getLoad()
return multi:newFunction(function(self) if multi.load_updater:isPaused() then multi.load_updater:Resume() return 0 end
multi.scheduler:Pause() local val = math.abs(self.dStepA-self.dStepB)/multi.deltaTarget*100
local sample=#multi.Mainloop if val > 100 then return 100 else return val end
local FFloadtest=0
multi:benchMark(multi.threstimed):OnBench(function(_,l3) FFloadtest=l3*(1/multi.threstimed) end)
self:hold(function() return FFloadtest~=0 end)
local val=FFloadtest/sample
multi.scheduler:Resume()
if val>multi.threshold then
return 0
else
return 100-((val/multi.threshold)*100)
end
end)()
end end
function multi:setDomainName(name) function multi:setDomainName(name)
self[name]={} self[name]={}
@ -195,6 +187,7 @@ multi.Condition=multi.condition
function multi:isHeld() function multi:isHeld()
return self.held return self.held
end end
multi.important={}
multi.IsHeld=multi.isHeld multi.IsHeld=multi.isHeld
function multi.executeFunction(name,...) function multi.executeFunction(name,...)
if type(_G[name])=='function' then if type(_G[name])=='function' then
@ -214,14 +207,39 @@ end
multi.WaitFor=multi.waitFor multi.WaitFor=multi.waitFor
function multi:reboot(r) function multi:reboot(r)
local before=collectgarbage('count') local before=collectgarbage('count')
self.Mainloop={} multi.Mainloop={}
self.Tasks={} multi.Tasks={}
self.Tasks2={} multi.Tasks2={}
self.Garbage={} multi.Garbage={}
self.Children={} multi.ender={}
self.Paused={} multi.Children={}
self.Active=true multi.Paused={}
self.Id=-1 multi.Active=true
multi.fps=60
multi.Id=-1
multi.Type='mainprocess'
multi.Rest=0
multi._type=type
multi.Jobs={}
multi.queue={}
multi.jobUS=2
multi.clock=os.clock
multi.time=os.time
multi.LinkedPath=multi
multi.isRunning=false
multi.Priority_Core=1
multi.Priority_High=4
multi.Priority_Above_Normal=16
multi.Priority_Normal=64
multi.Priority_Below_Normal=256
multi.Priority_Low=1024
multi.Priority_Idle=4096
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
multi.PStep=1
multi.PriorityTick=1
multi.Priority=multi.Priority_Core
multi.threshold=256
multi.threstimed=.001
if r then if r then
for i,v in pairs(_G) do for i,v in pairs(_G) do
if type(i)=='table' then if type(i)=='table' then
@ -280,20 +298,18 @@ function multi:enablePriority()
_G.ID=0 _G.ID=0
local PS=self local PS=self
for _D=#Loop,1,-1 do for _D=#Loop,1,-1 do
if Loop[_D] then for P=1,7 do
if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then if Loop[_D] then
if Loop[_D].Active then if (PS.PList[P])%Loop[_D].Priority==0 then
Loop[_D].Id=_D if Loop[_D].Active then
self.CID=_D Loop[_D].Id=_D
Loop[_D]:Act() self.CID=_D
Loop[_D]:Act()
end
end end
end end
end end
end end
PS.PStep=PS.PStep+1
if PS.PStep>7 then
PS.PStep=1
end
end end
end end
function multi:enablePriority2() function multi:enablePriority2()
@ -701,6 +717,7 @@ function multi:newProcess(file)
loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))() loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))()
end end
self:create(c) self:create(c)
--~ c:IngoreObject()
return c return c
end end
function multi:newQueuer(file) function multi:newQueuer(file)
@ -772,7 +789,8 @@ function multi:newTimer()
end end
function multi:newConnection(protect) function multi:newConnection(protect)
local c={} local c={}
setmetatable(c,{__call=function(self,...) self:connect(...) end}) c.Parent=self
setmetatable(c,{__call=function(self,...) return self:connect(...) end})
c.Type='connector' c.Type='connector'
c.func={} c.func={}
c.ID=0 c.ID=0
@ -780,6 +798,16 @@ function multi:newConnection(protect)
c.connections={} c.connections={}
c.fconnections={} c.fconnections={}
c.FC=0 c.FC=0
function c:holdUT()
self.waiting=true
local id=self:connect(function()
self.waiting=false
end)
repeat
self.Parent:uManager()
until self.waiting==false
id:Destroy()
end
function c:fConnect(func) function c:fConnect(func)
local temp=self:connect(func) local temp=self:connect(func)
table.insert(self.fconnections,temp) table.insert(self.fconnections,temp)
@ -852,8 +880,9 @@ function multi:newConnection(protect)
end end
end end
end end
end end,
} }
temp.Destroy=temp.Remove
if name then if name then
self.connections[name]=temp self.connections[name]=temp
end end
@ -1123,7 +1152,7 @@ function multi:newUpdater(skip)
end end
self.pos=self.pos+1 self.pos=self.pos+1
end end
function c:setSkip(n) function c:SetSkip(n)
self.skip=n self.skip=n
end end
c.OnUpdate=self.OnMainConnect c.OnUpdate=self.OnMainConnect
@ -1376,6 +1405,112 @@ function multi:newTStep(start,reset,count,set)
self:create(c) self:create(c)
return c return c
end end
function multi:newTimeStamper()
local c=self:newBase()
c.Type='timestamper'
c.Priority=self.Priority_Idle
c.hour = {}
c.minute = {}
c.second = {}
c.time = {}
c.day = {}
c.month = {}
c.year = {}
function c:Act()
for i=1,#self.hour do
if self.hour[i][1]==os.date("%H") and self.hour[i][3] then
self.hour[i][2](self)
self.hour[i][3]=false
elseif self.hour[i][1]~=os.date("%H") and not self.hour[i][3] then
self.hour[i][3]=true
end
end
for i=1,#self.minute do
if self.minute[i][1]==os.date("%M") and self.minute[i][3] then
self.minute[i][2](self)
self.minute[i][3]=false
elseif self.minute[i][1]~=os.date("%M") and not self.minute[i][3] then
self.minute[i][3]=true
end
end
for i=1,#self.second do
if self.second[i][1]==os.date("%S") and self.second[i][3] then
self.second[i][2](self)
self.second[i][3]=false
elseif self.second[i][1]~=os.date("%S") and not self.second[i][3] then
self.second[i][3]=true
end
end
for i=1,#self.day do
if type(self.day[i][1])=="string" then
if self.day[i][1]==os.date("%a") and self.day[i][3] then
self.day[i][2](self)
self.day[i][3]=false
elseif self.day[i][1]~=os.date("%a") and not self.day[i][3] then
self.day[i][3]=true
end
else
if string.format("%02d",self.day[i][1])==os.date("%d") and self.day[i][3] then
self.day[i][2](self)
self.day[i][3]=false
elseif string.format("%02d",self.day[i][1])~=os.date("%d") and not self.day[i][3] then
self.day[i][3]=true
end
end
end
for i=1,#self.month do
if self.month[i][1]==os.date("%m") and self.month[i][3] then
self.month[i][2](self)
self.month[i][3]=false
elseif self.month[i][1]~=os.date("%m") and not self.month[i][3] then
self.month[i][3]=true
end
end
for i=1,#self.time do
if self.time[i][1]==os.date("%X") and self.time[i][3] then
self.time[i][2](self)
self.time[i][3]=false
elseif self.time[i][1]~=os.date("%X") and not self.time[i][3] then
self.time[i][3]=true
end
end
for i=1,#self.year do
if self.year[i][1]==os.date("%y") and self.year[i][3] then
self.year[i][2](self)
self.year[i][3]=false
elseif self.year[i][1]~=os.date("%y") and not self.year[i][3] then
self.year[i][3]=true
end
end
end
function c:OnTime(hour,minute,second,func)
if type(hour)=="number" then
self.time[#self.time+1]={string.format("%02d:%02d:%02d",hour,minute,second),func,true}
else
self.time[#self.time+1]={hour,minute,true}
end
end
function c:OnHour(hour,func)
self.hour[#self.hour+1]={string.format("%02d",hour),func,true}
end
function c:OnMinute(minute,func)
self.minute[#self.minute+1]={string.format("%02d",minute),func,true}
end
function c:OnSecond(second,func)
self.second[#self.second+1]={string.format("%02d",second),func,true}
end
function c:OnDay(day,func)
self.day[#self.day+1]={day,func,true}
end
function c:OnMonth(month,func)
self.month[#self.month+1]={string.format("%02d",month),func,true}
end
function c:OnYear(year,func)
self.year[#self.year+1]={string.format("%02d",year),func,true}
end
self:create(c)
return c
end
function multi:newWatcher(namespace,name) function multi:newWatcher(namespace,name)
local function WatcherObj(ns,n) local function WatcherObj(ns,n)
if self.Type=='queue' then if self.Type=='queue' then
@ -1462,6 +1597,7 @@ function multi:newTBase(name)
c.important={} c.important={}
c.held=false c.held=false
c.ToString=multi.ToString c.ToString=multi.ToString
c.ToFile=multi.ToFile
return c return c
end end
function multi:newThread(name,func) function multi:newThread(name,func)
@ -1992,9 +2128,15 @@ function multi:newThreadedEvent(name,task)
return c return c
end end
-- State Saving Stuff -- State Saving Stuff
function multi:IngoreObject()
self.Ingore=true
end
multi.scheduler:IngoreObject()
function multi:ToString() function multi:ToString()
if self.Ingore then return end
local t=self.Type local t=self.Type
local data; local data;
print(t)
if t:sub(-6)=="Thread" then if t:sub(-6)=="Thread" then
data={ data={
Type=t, Type=t,
@ -2025,9 +2167,7 @@ function multi:ToString()
held=self.held, held=self.held,
} }
end end
if t=="process" then if t=="eventThread" or t=="event" then
--
elseif t=="eventThread" or t=="event" then
table.merge(data,{ table.merge(data,{
Task=self.Task, Task=self.Task,
}) })
@ -2095,6 +2235,23 @@ function multi:ToString()
set=self.set, set=self.set,
link=self.link, link=self.link,
}) })
elseif t=="process" or t=="mainprocess" then
local loop=self.Mainloop
local dat={}
for i=1,#loop do
local ins=loop[i]:ToString()
if ins~=nil then
table.insert(dat,ins)
end
end
local str=bin.new()
str:addBlock({Type=t})
str:addBlock(#dat,4,"n")
for i=1,#dat do
str:addBlock(#dat[i],4,"n")
str:addBlock(dat[i])
end
return str.data
end end
for i,v in pairs(self.important) do for i,v in pairs(self.important) do
data[v]=self[v] data[v]=self[v]
@ -2109,9 +2266,23 @@ function multi:newFromString(str)
str=str.data str=str.data
end end
end end
local data=bin.new(str):getBlock("t") local handle=bin.new(str)
local data=handle:getBlock("t")
local t=data.Type local t=data.Type
if t=="step" then -- GOOD if t=="mainprocess" then
local objs=handle:getBlock("n",4)
for i=1,objs do
self:newFromString(handle:getBlock("s",(handle:getBlock("n",4))))
end
return self
elseif t=="process" then
local temp=multi:newProcess()
local objs=handle:getBlock("n",4)
for i=1,objs do
temp:newFromString(handle:getBlock("s",(handle:getBlock("n",4))))
end
return temp
elseif t=="step" then -- GOOD
local item=self:newStep() local item=self:newStep()
table.merge(item,data) table.merge(item,data)
return item return item
@ -2176,6 +2347,12 @@ end
function multi:Important(varname) function multi:Important(varname)
table.insert(important,varname) table.insert(important,varname)
end end
function multi:ToFile(path)
bin.new(self:ToString()):tofile(path)
end
function multi:fromFile(path)
self:newFromString(bin.load(path))
end
function multi:SetStateFlag(opt) function multi:SetStateFlag(opt)
-- --
end end
@ -2191,3 +2368,18 @@ end
function multi:setDefualtStateFlag(opt) function multi:setDefualtStateFlag(opt)
-- --
end end
multi.dStepA = 0
multi.dStepB = 0
multi.dSwap = 0
multi.deltaTarget = .05
multi.load_updater = multi:newUpdater(2)
multi.load_updater:Pause()
multi.load_updater:OnUpdate(function(self)
if self.Parent.dSwap == 0 then
self.Parent.dStepA = os.clock()
self.Parent.dSwap = 1
else
self.Parent.dSwap = 0
self.Parent.dStepB = os.clock()
end
end)

View File

@ -89,7 +89,10 @@ else
THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n")) THREAD.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
end end
function THREAD.kill() -- trigger the lane destruction function THREAD.kill() -- trigger the lane destruction
-- coroutine.yield({"_kill_",":)"}) error("Thread was killed!")
end
function THREAD.getName()
return THREAD_NAME
end end
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait --[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
@ -111,7 +114,12 @@ function multi:newSystemThread(name,func,...)
local __self=c local __self=c
c.name=name c.name=name
c.Type="sthread" c.Type="sthread"
c.thread=lanes.gen("*", func)(...) local THREAD_NAME=name
local function func2(...)
_G["THREAD_NAME"]=THREAD_NAME
func()
end
c.thread=lanes.gen("*", func2)(...)
function c:kill() function c:kill()
--self.status:Destroy() --self.status:Destroy()
self.thread:cancel() self.thread:cancel()

View File

@ -9,11 +9,12 @@ multi.integration={}
multi.integration.love2d={} multi.integration.love2d={}
multi.integration.love2d.ThreadBase=[[ multi.integration.love2d.ThreadBase=[[
tab={...} tab={...}
__THREADID__=table.remove(1,tab) __THREADID__=table.remove(tab,1)
__THREADNAME__=table.remove(1,tab) __THREADNAME__=table.remove(tab,1)
require("love.filesystem") require("love.filesystem")
require("love.system") require("love.system")
require("love.timer") require("love.timer")
require("love.image")
require("multi") require("multi")
GLOBAL={} GLOBAL={}
setmetatable(GLOBAL,{ setmetatable(GLOBAL,{
@ -34,7 +35,7 @@ setmetatable(GLOBAL,{
function __sync__() function __sync__()
local data=__mythread__:pop() local data=__mythread__:pop()
while data do while data do
love.timer.sleep(.001) love.timer.sleep(.01)
if type(data)=="string" then if type(data)=="string" then
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)") local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
if name=="__DIEPLZ"..__THREADID__.."__" then if name=="__DIEPLZ"..__THREADID__.."__" then
@ -139,6 +140,12 @@ function dump(func)
end end
return table.concat(code) return table.concat(code)
end end
function sThread.getName()
return __THREADNAME__
end
function sThread.kill()
error("Thread was killed!")
end
function sThread.set(name,val) function sThread.set(name,val)
GLOBAL[name]=val GLOBAL[name]=val
end end
@ -158,14 +165,6 @@ end
function sThread.hold(n) function sThread.hold(n)
repeat __sync__() until n() repeat __sync__() until n()
end end
multi:newLoop(function(self)
self:Pause()
local ld=multi:getLoad()
self:Resume()
if ld<80 then
love.timer.sleep(.01)
end
end)
updater=multi:newUpdater() updater=multi:newUpdater()
updater:OnUpdate(__sync__) updater:OnUpdate(__sync__)
func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab)) func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab))
@ -190,6 +189,9 @@ setmetatable(GLOBAL,{
}) })
THREAD={} -- Allow main thread to interact with these objects as well THREAD={} -- Allow main thread to interact with these objects as well
multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__") multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
function THREAD.getName()
return __THREADNAME__
end
function ToStr(val, name, skipnewlines, depth) function ToStr(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false skipnewlines = skipnewlines or false
depth = depth or 0 depth = depth or 0

View File

@ -37,19 +37,62 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
function c:init() -- create an init function so we can mimic on bith love2d and lanes function c:init() -- create an init function so we can mimic on bith love2d and lanes
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
function self:push(v) -- push to the channel function self:push(v) -- push to the channel
self.chan:push({type(v),resolveData(v)}) local tab
if type(v)=="table" then
tab = {}
for i,c in pairs(v) do
if type(c)=="function" then
tab[i]="\1"..string.dump(c)
else
tab[i]=c
end
end
self.chan:push(tab)
else
self.chan:push(c)
end
end end
function self:pop() -- pop from the channel function self:pop() -- pop from the channel
local tab=self.chan:pop() local v=self.chan:pop()
--print(tab) if not v then return end
if not tab then return end if type(v)=="table" then
return resolveType(tab[1],tab[2]) tab = {}
for i,c in pairs(v) do
if type(c)=="string" then
if c:sub(1,1)=="\1" then
tab[i]=loadstring(c:sub(2,-1))
else
tab[i]=c
end
else
tab[i]=c
end
end
return tab
else
return self.chan:pop()
end
end end
function self:peek() function self:peek()
local tab=self.chan:peek() local v=self.chan:peek()
--print(tab) if not v then return end
if not tab then return end if type(v)=="table" then
return resolveType(tab[1],tab[2]) tab = {}
for i,c in pairs(v) do
if type(c)=="string" then
if c:sub(1,1)=="\1" then
tab[i]=loadstring(c:sub(2,-1))
else
tab[i]=c
end
else
tab[i]=c
end
end
return tab
else
return self.chan:pop()
end
end end
GLOBAL[self.name]=self -- send the object to the thread through the global interface GLOBAL[self.name]=self -- send the object to the thread through the global interface
return self -- return the object return self -- return the object
@ -120,7 +163,7 @@ function multi:systemThreadedBenchmark(n,p)
end) end)
return c return c
end end
function multi:newSystemThreadedTable(name,n) function multi:newSystemThreadedTable(name,n) -- NEDS FIXING SING SO MUCH WORK!!!
local c={} -- where we will store our object local c={} -- where we will store our object
c.name=name -- set the name this is important for the love2d side c.name=name -- set the name this is important for the love2d side
c.cores=n c.cores=n
@ -212,8 +255,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init() c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init()
c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init() c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init()
c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init() c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init()
-- registerJob(name,func) c.OnReady=multi:newConnection()
-- pushJob(...)
function c:registerJob(name,func) function c:registerJob(name,func)
for i=1,self.cores do for i=1,self.cores do
self.REG:push({name,func}) self.REG:push({name,func})
@ -222,6 +264,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
function c:pushJob(name,...) function c:pushJob(name,...)
self.queueOUT:push({self.jobnum,name,...}) self.queueOUT:push({self.jobnum,name,...})
self.jobnum=self.jobnum+1 self.jobnum=self.jobnum+1
return self.jobnum-1
end end
local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes local GLOBAL=multi.integration.GLOBAL -- set up locals incase we are using lanes
local sThread=multi.integration.THREAD -- set up locals incase we are using lanes local sThread=multi.integration.THREAD -- set up locals incase we are using lanes
@ -232,15 +275,24 @@ function multi:newSystemThreadedJobQueue(numOfCores)
end end
end end
function c:start() function c:start()
self:doToAll(function() multi:newEvent(function()
_G["__started__"]=true return self.ThreadsLoaded==true
SFunc() end):OnEvent(function(evnt)
GLOBAL["THREADED_JQ"]=nil -- remove it
GLOBAL["THREADED_JQO"]=nil -- remove it
GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it
self:doToAll(function()
_G["__started__"]=true
SFunc()
end)
evnt:Destroy()
end) end)
end end
GLOBAL["__JQ_COUNT__"]=c.cores GLOBAL["__JQ_COUNT__"]=c.cores
for i=1,c.cores do for i=1,c.cores do
multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function() multi:newSystemThread("System Threaded Job Queue Worker Thread #"..i,function(name,ind)
require("multi") require("multi")
ThreadName=name
__sleep__=.001 __sleep__=.001
if love then -- lets make sure we don't reference upvalues if using love2d if love then -- lets make sure we don't reference upvalues if using love2d
GLOBAL=_G.GLOBAL GLOBAL=_G.GLOBAL
@ -251,10 +303,6 @@ function multi:newSystemThreadedJobQueue(numOfCores)
JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it
REG=sThread.waitFor("THREADED_JQ_F_REG"):init() -- Grab it REG=sThread.waitFor("THREADED_JQ_F_REG"):init() -- Grab it
QALL=sThread.waitFor("THREADED_QALL"):init() -- Grab it QALL=sThread.waitFor("THREADED_QALL"):init() -- Grab it
sThread.sleep(.1) -- lets wait for things to work out
GLOBAL["THREADED_JQ"]=nil -- remove it
GLOBAL["THREADED_JQO"]=nil -- remove it
GLOBAL["THREADED_JQ_F_REG"]=nil -- remove it
QALLT={} QALLT={}
FUNCS={} FUNCS={}
SFunc=multi:newFunction(function(self) SFunc=multi:newFunction(function(self)
@ -287,10 +335,12 @@ function multi:newSystemThreadedJobQueue(numOfCores)
return FUNCS[k] return FUNCS[k]
end end
}) })
lastjob=os.clock()
MainLoop=multi:newLoop(function(self) MainLoop=multi:newLoop(function(self)
if __started__ then if __started__ then
local job=JQI:pop() local job=JQI:pop()
if job then if job then
lastjob=os.clock()
local d=QALL:peek() local d=QALL:peek()
if d then if d then
if not QALLT[d[1]] then if not QALLT[d[1]] then
@ -311,17 +361,34 @@ function multi:newSystemThreadedJobQueue(numOfCores)
end end
end end
end) end)
multi:newThread("Idler",function()
while true do
if os.clock()-lastjob>1 then
sThread.sleep(.1)
end
thread.sleep(.001)
end
end)
JQO:push({"_THREADINIT_",ind})
if not love then if not love then
multi:mainloop() multi:mainloop()
end end
end) end,"Thread<"..i..">",i)
end end
c.OnJobCompleted=multi:newConnection() c.OnJobCompleted=multi:newConnection()
c.updater=multi:newLoop(function(self) c.updater=multi:newLoop(function(self)
local data=self.link.queueIN:pop() local data=self.link.queueIN:pop()
while data do while data do
if data then if data then
self.link.OnJobCompleted:Fire(unpack(data)) local a,b=unpack(data)
if a=="_THREADINIT_" then
if b==self.link.cores then
self.link.ThreadsLoaded=true
self.link.OnReady:Fire()
end
else
self.link.OnJobCompleted:Fire(unpack(data))
end
end end
data=self.link.queueIN:pop() data=self.link.queueIN:pop()
end end

View File

@ -0,0 +1,33 @@
package = "multi"
version = "1.9-2"
source = {
url = "git://github.com/rayaman/multi.git",
tag = "v1.9.1",
}
description = {
summary = "Lua Multi tasking library",
detailed = [[
This library contains many methods for multi tasking. From simple side by side code using multiobjs, to using coroutine based Threads and System threads(When you have lua lanes installed or are using love2d. Optional) The core of the library works on lua 5.1+ however the systemthreading features are limited to 5.1 due to love2d and lua lanes and now luvit (See ReadMe on gotchas) being lua 5.1 only!
]],
homepage = "https://github.com/rayaman/multi",
license = "MIT"
}
dependencies = {
"lua >= 5.1",
"bin",
"lanes"
}
build = {
type = "builtin",
modules = {
-- Note the required Lua syntax when listing submodules as keys
["multi.init"] = "multi/init.lua",
["multi.all"] = "multi/all.lua",
["multi.compat.backwards[1,5,0]"] = "multi/compat/backwards[1,5,0].lua",
["multi.compat.love2d"] = "multi/compat/love2d.lua",
["multi.integration.lanesManager"] = "multi/integration/lanesManager.lua",
["multi.integration.loveManager"] = "multi/integration/loveManager.lua",
["multi.integration.luvitManager"] = "multi/integration/luvitManager.lua",
["multi.integration.shared"] = "multi/integration/shared.lua"
}
}

BIN
test.dat

Binary file not shown.