diff --git a/PManager.txt b/PManager.txt new file mode 100644 index 0000000..11dab87 --- /dev/null +++ b/PManager.txt @@ -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 \ No newline at end of file diff --git a/README.html b/README.html index eb7824c..ed8067c 100644 --- a/README.html +++ b/README.html @@ -9,7 +9,7 @@
-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):
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
In Changes you’ll find documentation for(In Order):
My multitasking library for lua. It is a pure lua binding if you ingore the integrations and the love2d compat. If you find any bugs or have any issues please let me know :). If you don’t see a table of contents try using the ReadMe.html file. It is eaiser to navigate the readme
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.
https://discord.gg/U8UspuA
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.
https://discord.gg/U8UspuA
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 regards to integrations, thread cancellation works slightly different for love2d and lanes. Within love2d I was unable to (To lazy to…) not use the multi library within the thread. A fix for this is to call multi:Stop() when you are done with your threaded code! This may change however if I find a way to work around this. In love2d in order to mimic the GLOBAL table I needed the library to constantly sync tha data… You can use the sThread.waitFor(varname), or sThread.hold(func) methods to sync the globals, to get the value instead of using GLOBAL and this could work. If you want to go this route I suggest setting multi.isRunning=true to prevent the auto runner from doing its thing! This will make the multi manager no longer function, but thats the point :P
Another bug concerns the SystemThreadedJobQueue, Only 1 can be used for now… Creating more may not be a good idea.
And systemThreadedTables only supports 1 table between the main and worker thread! They do not work when shared between 2 or more threads. If you need that much flexiblity ust the GLOBAL table that all threads have.
For module creators using this library. I suggest using SystemThreadedQueues for data transfer instead of SystemThreadedTables for rapid data transfer, If you plan on having Constants that will always be the same then a table is a good idea! They support up to n threads and can be messed with and abused as much as you want :D
Love2D SystemThreadedTAbles do not send love2d userdata, use queues instead for that!
function<
end
end)
multi:mainloop()
-Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Loop timed out! tloop Trying again…
Looping…
Looping…
Looping…
Looping…
Looping…
We did it! 1 2 3
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,…)
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
Added:
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Looping…
Loop timed out! tloop Trying again…
Looping…
Looping…
Looping…
Looping…
Looping…
We did it! 1 2 3
Added:
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:Fixed:
Changed:
Added:
Updated:
Added:
Works on threads and regular objects. Requires the latest bin library to work!
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)
diff --git a/multi/integration/lanesManager.lua b/multi/integration/lanesManager.lua
index f650df4..d71f252 100644
--- a/multi/integration/lanesManager.lua
+++ b/multi/integration/lanesManager.lua
@@ -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()
diff --git a/multi/integration/loveManager.lua b/multi/integration/loveManager.lua
index ef7ba6d..04c09fa 100644
--- a/multi/integration/loveManager.lua
+++ b/multi/integration/loveManager.lua
@@ -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
diff --git a/multi/integration/shared.lua b/multi/integration/shared.lua
index 63ff000..37aeaa4 100644
--- a/multi/integration/shared.lua
+++ b/multi/integration/shared.lua
@@ -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
diff --git a/rockspecs/multi-1.9-2.rockspec b/rockspecs/multi-1.9-2.rockspec
new file mode 100644
index 0000000..6ce750b
--- /dev/null
+++ b/rockspecs/multi-1.9-2.rockspec
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/test.dat b/test.dat
index 03e1c8e..1bff574 100644
Binary files a/test.dat and b/test.dat differ