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**
**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):
- Sterilizing Objects
- 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>
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
---------------------
- [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
-------
Update: 1.9.1
Update: 1.9.2
-------------
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.
- (THREAD).kill() kills a thread. Note: THREAD is based on what you name it
- newTimeStamper() Part of the persistant systems... Useful for when you are running this library for a massive amount of time... like years stright!
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:
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
-------------
Added:

View File

@ -32,7 +32,7 @@ multi:newThread("test0",function()
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...
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

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()
jQueue=multi:newSystemThreadedJobQueue(n)
jQueue:registerJob("TEST_JOB",function(a,s)
@ -11,7 +11,7 @@ jQueue:registerJob("TEST_JOB2",function()
end)
jQueue:start()
jQueue:doToAll(function()
print("Doing this 6? times!")
print("Doing this 16? times!")
end)
for i=1,10 do -- Job Name of registered function, ... varargs
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.
]]
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
unpack=table.unpack
end
@ -45,83 +101,19 @@ function print(...)
_print(...)
end
end
multi = {}
multi.Version="1.9.1"
multi._VERSION="1.9.1"
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
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()
_write=io.write
function io.write(...)
if not __SUPPRESSWRITES then
_write(...)
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)
self.threstimed=n or .001
self.deltaTarget=n or .1
end
function multi:getLoad()
return multi:newFunction(function(self)
multi.scheduler:Pause()
local sample=#multi.Mainloop
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)()
if multi.load_updater:isPaused() then multi.load_updater:Resume() return 0 end
local val = math.abs(self.dStepA-self.dStepB)/multi.deltaTarget*100
if val > 100 then return 100 else return val end
end
function multi:setDomainName(name)
self[name]={}
@ -195,6 +187,7 @@ multi.Condition=multi.condition
function multi:isHeld()
return self.held
end
multi.important={}
multi.IsHeld=multi.isHeld
function multi.executeFunction(name,...)
if type(_G[name])=='function' then
@ -214,14 +207,39 @@ end
multi.WaitFor=multi.waitFor
function multi:reboot(r)
local before=collectgarbage('count')
self.Mainloop={}
self.Tasks={}
self.Tasks2={}
self.Garbage={}
self.Children={}
self.Paused={}
self.Active=true
self.Id=-1
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.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
for i,v in pairs(_G) do
if type(i)=='table' then
@ -280,20 +298,18 @@ function multi:enablePriority()
_G.ID=0
local PS=self
for _D=#Loop,1,-1 do
if Loop[_D] then
if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
if Loop[_D].Active then
Loop[_D].Id=_D
self.CID=_D
Loop[_D]:Act()
for P=1,7 do
if Loop[_D] then
if (PS.PList[P])%Loop[_D].Priority==0 then
if Loop[_D].Active then
Loop[_D].Id=_D
self.CID=_D
Loop[_D]:Act()
end
end
end
end
end
PS.PStep=PS.PStep+1
if PS.PStep>7 then
PS.PStep=1
end
end
end
function multi:enablePriority2()
@ -701,6 +717,7 @@ function multi:newProcess(file)
loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))()
end
self:create(c)
--~ c:IngoreObject()
return c
end
function multi:newQueuer(file)
@ -772,7 +789,8 @@ function multi:newTimer()
end
function multi:newConnection(protect)
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.func={}
c.ID=0
@ -780,6 +798,16 @@ function multi:newConnection(protect)
c.connections={}
c.fconnections={}
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)
local temp=self:connect(func)
table.insert(self.fconnections,temp)
@ -852,8 +880,9 @@ function multi:newConnection(protect)
end
end
end
end
end,
}
temp.Destroy=temp.Remove
if name then
self.connections[name]=temp
end
@ -1123,7 +1152,7 @@ function multi:newUpdater(skip)
end
self.pos=self.pos+1
end
function c:setSkip(n)
function c:SetSkip(n)
self.skip=n
end
c.OnUpdate=self.OnMainConnect
@ -1376,6 +1405,112 @@ function multi:newTStep(start,reset,count,set)
self:create(c)
return c
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)
local function WatcherObj(ns,n)
if self.Type=='queue' then
@ -1462,6 +1597,7 @@ function multi:newTBase(name)
c.important={}
c.held=false
c.ToString=multi.ToString
c.ToFile=multi.ToFile
return c
end
function multi:newThread(name,func)
@ -1992,9 +2128,15 @@ function multi:newThreadedEvent(name,task)
return c
end
-- State Saving Stuff
function multi:IngoreObject()
self.Ingore=true
end
multi.scheduler:IngoreObject()
function multi:ToString()
if self.Ingore then return end
local t=self.Type
local data;
print(t)
if t:sub(-6)=="Thread" then
data={
Type=t,
@ -2025,9 +2167,7 @@ function multi:ToString()
held=self.held,
}
end
if t=="process" then
--
elseif t=="eventThread" or t=="event" then
if t=="eventThread" or t=="event" then
table.merge(data,{
Task=self.Task,
})
@ -2095,6 +2235,23 @@ function multi:ToString()
set=self.set,
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
for i,v in pairs(self.important) do
data[v]=self[v]
@ -2109,9 +2266,23 @@ function multi:newFromString(str)
str=str.data
end
end
local data=bin.new(str):getBlock("t")
local handle=bin.new(str)
local data=handle:getBlock("t")
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()
table.merge(item,data)
return item
@ -2176,6 +2347,12 @@ end
function multi:Important(varname)
table.insert(important,varname)
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)
--
end
@ -2191,3 +2368,18 @@ end
function multi:setDefualtStateFlag(opt)
--
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"))
end
function THREAD.kill() -- trigger the lane destruction
-- coroutine.yield({"_kill_",":)"})
error("Thread was killed!")
end
function THREAD.getName()
return THREAD_NAME
end
--[[ 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
@ -111,7 +114,12 @@ function multi:newSystemThread(name,func,...)
local __self=c
c.name=name
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()
--self.status:Destroy()
self.thread:cancel()

View File

@ -9,11 +9,12 @@ multi.integration={}
multi.integration.love2d={}
multi.integration.love2d.ThreadBase=[[
tab={...}
__THREADID__=table.remove(1,tab)
__THREADNAME__=table.remove(1,tab)
__THREADID__=table.remove(tab,1)
__THREADNAME__=table.remove(tab,1)
require("love.filesystem")
require("love.system")
require("love.timer")
require("love.image")
require("multi")
GLOBAL={}
setmetatable(GLOBAL,{
@ -34,7 +35,7 @@ setmetatable(GLOBAL,{
function __sync__()
local data=__mythread__:pop()
while data do
love.timer.sleep(.001)
love.timer.sleep(.01)
if type(data)=="string" then
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
if name=="__DIEPLZ"..__THREADID__.."__" then
@ -139,6 +140,12 @@ function dump(func)
end
return table.concat(code)
end
function sThread.getName()
return __THREADNAME__
end
function sThread.kill()
error("Thread was killed!")
end
function sThread.set(name,val)
GLOBAL[name]=val
end
@ -158,14 +165,6 @@ end
function sThread.hold(n)
repeat __sync__() until n()
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:OnUpdate(__sync__)
func=loadDump([=[INSERT_USER_CODE]=])(unpack(tab))
@ -190,6 +189,9 @@ setmetatable(GLOBAL,{
})
THREAD={} -- Allow main thread to interact with these objects as well
multi.integration.love2d.mainChannel=love.thread.getChannel("__MainChan__")
function THREAD.getName()
return __THREADNAME__
end
function ToStr(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
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
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
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
function self:pop() -- pop from the channel
local tab=self.chan:pop()
--print(tab)
if not tab then return end
return resolveType(tab[1],tab[2])
local v=self.chan:pop()
if not v then return end
if type(v)=="table" then
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
function self:peek()
local tab=self.chan:peek()
--print(tab)
if not tab then return end
return resolveType(tab[1],tab[2])
local v=self.chan:peek()
if not v then return end
if type(v)=="table" then
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
GLOBAL[self.name]=self -- send the object to the thread through the global interface
return self -- return the object
@ -120,7 +163,7 @@ function multi:systemThreadedBenchmark(n,p)
end)
return c
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
c.name=name -- set the name this is important for the love2d side
c.cores=n
@ -212,8 +255,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
c.queueOUT=multi:newSystemThreadedQueue("THREADED_JQO"):init()
c.queueALL=multi:newSystemThreadedQueue("THREADED_QALL"):init()
c.REG=multi:newSystemThreadedQueue("THREADED_JQ_F_REG"):init()
-- registerJob(name,func)
-- pushJob(...)
c.OnReady=multi:newConnection()
function c:registerJob(name,func)
for i=1,self.cores do
self.REG:push({name,func})
@ -222,6 +264,7 @@ function multi:newSystemThreadedJobQueue(numOfCores)
function c:pushJob(name,...)
self.queueOUT:push({self.jobnum,name,...})
self.jobnum=self.jobnum+1
return self.jobnum-1
end
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
@ -232,15 +275,24 @@ function multi:newSystemThreadedJobQueue(numOfCores)
end
end
function c:start()
self:doToAll(function()
_G["__started__"]=true
SFunc()
multi:newEvent(function()
return self.ThreadsLoaded==true
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
GLOBAL["__JQ_COUNT__"]=c.cores
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")
ThreadName=name
__sleep__=.001
if love then -- lets make sure we don't reference upvalues if using love2d
GLOBAL=_G.GLOBAL
@ -251,10 +303,6 @@ function multi:newSystemThreadedJobQueue(numOfCores)
JQO=sThread.waitFor("THREADED_JQ"):init() -- Grab it
REG=sThread.waitFor("THREADED_JQ_F_REG"):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={}
FUNCS={}
SFunc=multi:newFunction(function(self)
@ -287,10 +335,12 @@ function multi:newSystemThreadedJobQueue(numOfCores)
return FUNCS[k]
end
})
lastjob=os.clock()
MainLoop=multi:newLoop(function(self)
if __started__ then
local job=JQI:pop()
if job then
lastjob=os.clock()
local d=QALL:peek()
if d then
if not QALLT[d[1]] then
@ -311,17 +361,34 @@ function multi:newSystemThreadedJobQueue(numOfCores)
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
multi:mainloop()
end
end)
end,"Thread<"..i..">",i)
end
c.OnJobCompleted=multi:newConnection()
c.updater=multi:newLoop(function(self)
local data=self.link.queueIN:pop()
while data do
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
data=self.link.queueIN:pop()
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.