Updated to version (1.8.2)
Added more example files Added SystemThreadedTables Some bug fixes
This commit is contained in:
parent
4c3c09a109
commit
a414def307
80
README.html
80
README.html
File diff suppressed because one or more lines are too long
74
README.md
74
README.md
@ -1,4 +1,4 @@
|
|||||||
# multi Version: 1.8.1
|
# multi Version: 1.8.2 (More support for love & lanes threading!)
|
||||||
**Note: The changes section has information on how to use the new features as they come out. Why put the infomation twice on the readme?**</br>
|
**Note: The changes section has information on how to use the new features as they come out. Why put the infomation twice on the readme?**</br>
|
||||||
|
|
||||||
My multitasking library for lua</br>
|
My multitasking library for lua</br>
|
||||||
@ -8,25 +8,23 @@ It is a pure lua binding if you ingore the intergrations and the love2d compat</
|
|||||||
|
|
||||||
If you find any bugs or have any issues please let me know :)
|
If you find any bugs or have any issues please let me know :)
|
||||||
|
|
||||||
~~Also I will eventually add an example folder with a lot of examples for how you can use this library. Don't konw when that will be though :P~~ Added!
|
|
||||||
|
|
||||||
|
|
||||||
[TOC]
|
[TOC]
|
||||||
|
|
||||||
Discord
|
Discord
|
||||||
-------
|
-------
|
||||||
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries</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>
|
||||||
|
|
||||||
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).~~
|
||||||
- [ ] Improve performance of the library -- It has increased a bit, but I feel I can get a little more out of it
|
- [ ] Improve performance of the library -- It has increased a bit, but I feel I can get a little more out of it
|
||||||
|
- [ ] Improve coroutine based threading scheduling
|
||||||
- [x] ~~Add more features to support module creators~~
|
- [x] ~~Add more features to support module creators~~
|
||||||
- [x] ~~Make a framework for eaiser thread task distributing~~
|
- [x] ~~Make a framework for eaiser thread task distributing~~
|
||||||
- [x] ~~Fix Error handling on threaded multi objects~~ Non threaded multiobjs will crash your program if they error though! Use multi:newThread() of multi:newSystemThread() if your code can error! Unless you use multi:protect() this however lowers performance!
|
- [x] ~~Fix Error handling on threaded multi objects~~ Non threaded multiobjs will crash your program if they error though! Use multi:newThread() of multi:newSystemThread() if your code can error! Unless you use multi:protect() this however lowers performance!
|
||||||
- [x] ~~Add multi:OnError(function(obj,err))~~
|
- [x] ~~Add multi:OnError(function(obj,err))~~
|
||||||
- [ ] sThread.wrapper(obj) **May or may not be completed**
|
- [ ] sThread.wrap(obj) **May or may not be completed** Theory: Allows interaction in one thread to affect it in another. The addition to threaded tables may make this possible!
|
||||||
- [ ] SystemThreaded Actors -- After some tests i figured out a way to make this work... It will work slightly different though. This is due to the actor needing to be splittable...
|
- [ ] SystemThreaded Actors -- After some tests i figured out a way to make this work... It will work slightly different though. This is due to the actor needing to be splittable...
|
||||||
- [ ] LoadBalancing for system threads (Once SystemThreaded Actors are done)
|
- [ ] LoadBalancing for system threads (Once SystemThreaded Actors are done)
|
||||||
- [ ] Add more intergrations
|
- [ ] Add more intergrations
|
||||||
@ -788,6 +786,69 @@ We did it! 1 2 3</br>
|
|||||||
|
|
||||||
Changes
|
Changes
|
||||||
-------
|
-------
|
||||||
|
Updated from 1.8.1 to 1.8.2</br>
|
||||||
|
Added:</br>
|
||||||
|
- multi:newsystemThreadedTable(name) NOTE: Metatables are not supported in transfers. However there is a work around obj:init() that you see does this. Take a look in the multi/intergration/shared/shared.lua files to see how I did it!
|
||||||
|
- Modified the GLOBAL metatable to sync before doing its tests
|
||||||
|
- multi._VERSION was multi.Version, felt it would be more consistant this way... I left the old way of getting the version just incase someone has used that way. It will eventually be gone. Also multi:getVersion() will do the job just as well and keep your code nice and update related bug free!
|
||||||
|
- Also everything that is included in the: multi/intergration/shared/shared.lua (Which is loaded automatically) works in both lanes and love2d enviroments!
|
||||||
|
|
||||||
|
The threaded table is setup just like the threaded queue.</br>
|
||||||
|
It provids GLOBAL like features without having to write to GLOBAL!</br>
|
||||||
|
This is useful for module creators who want to keep their data private, but also use GLOBAL like coding.</br>
|
||||||
|
It has a few features that makes it a bit better than plain ol GLOBAL (For now...)
|
||||||
|
(ThreadedTable - TT for short)
|
||||||
|
- TT:waitFor(name)
|
||||||
|
- TT:sync()
|
||||||
|
- TT["var"]=value
|
||||||
|
- print(TT["var"])
|
||||||
|
|
||||||
|
we also have the "sync" method, this one was made for love2d because we do a syncing trick to get data in a table format. The lanes side has a sync method as well so no worries. Using indexing calls sync once and may grab your variable. This allows you to have the lanes indexing 'like' syntax when doing regular indexing in love2d side of the module. As of right now both sides work flawlessly! And this effect is now the GLOBAL as well</br>
|
||||||
|
|
||||||
|
On GLOBALS sync is a internal method for keeping the GLOBAL table in order. You can still use sThread.waitFor(name) to wait for variables that may of may not yet exist!
|
||||||
|
|
||||||
|
Time for some examples:
|
||||||
|
# Using multi:newSystemThreadedTable(name)
|
||||||
|
```lua
|
||||||
|
-- lanes Desktop lua! NOTE: this is in lanesintergratetest6.lua in the examples folder
|
||||||
|
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab:has("test1"))
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
|
```
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- love2d gaming lua! NOTE: this is in main4.lua in the love2d examples
|
||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.intergration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
require("core.GuiManager")
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab["test1"])
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
t.text="DONE!"
|
||||||
|
end)
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
|
```
|
||||||
|
|
||||||
Updated from 1.8.0 to 1.8.1</br>
|
Updated from 1.8.0 to 1.8.1</br>
|
||||||
No real change!</br>
|
No real change!</br>
|
||||||
Changed the structure of the library. Combined the coroutine based threads into the core!</br>
|
Changed the structure of the library. Combined the coroutine based threads into the core!</br>
|
||||||
@ -814,6 +875,7 @@ multi:mainloop()
|
|||||||
```
|
```
|
||||||
|
|
||||||
# Using multi:newSystemThreadedQueue()
|
# Using multi:newSystemThreadedQueue()
|
||||||
|
Quick Note: queues shared across multiple objects will be pulling from the same "queue" keep this in mind when coding! Also the queue respects direction a push on the thread side cannot be popped on the thread side... Same goes for the mainthread!</br>
|
||||||
```lua
|
```lua
|
||||||
-- in love2d, this file will be in the same example folder as before, but is named main2.lua
|
-- in love2d, this file will be in the same example folder as before, but is named main2.lua
|
||||||
require("core.Library")
|
require("core.Library")
|
||||||
|
|||||||
14
examples/lanesintergratetest6.lua
Normal file
14
examples/lanesintergratetest6.lua
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- lanes Desktop lua! NOTE: this is in lanesintergratetest6.lua in the examples folder
|
||||||
|
local GLOBAL,sThread=require("multi.intergration.lanesManager").init()
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab["test1"])
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
19
examples/love2d Threading Example/main4.lua
Normal file
19
examples/love2d Threading Example/main4.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require("core.Library")
|
||||||
|
GLOBAL,sThread=require("multi.intergration.loveManager").init() -- load the love2d version of the lanesManager and requires the entire multi library
|
||||||
|
require("core.GuiManager")
|
||||||
|
gui.ff.Color=Color.Black
|
||||||
|
test=multi:newSystemThreadedTable("YO"):init()
|
||||||
|
test["test1"]="lol"
|
||||||
|
multi:newSystemThread("test",function()
|
||||||
|
tab=sThread.waitFor("YO"):init()
|
||||||
|
print(tab["test1"])
|
||||||
|
sThread.sleep(3)
|
||||||
|
tab["test2"]="Whats so funny?"
|
||||||
|
end)
|
||||||
|
multi:newThread("test2",function()
|
||||||
|
print(test:waitFor("test2"))
|
||||||
|
t.text="DONE!"
|
||||||
|
end)
|
||||||
|
t=gui:newTextLabel("no done yet!",0,0,300,100)
|
||||||
|
t:centerX()
|
||||||
|
t:centerY()
|
||||||
@ -1,9 +1 @@
|
|||||||
require("multi")
|
require("multi")
|
||||||
require("multi.threading")
|
|
||||||
require("multi.threading.alarm")
|
|
||||||
require("multi.threading.event")
|
|
||||||
require("multi.threading.loop")
|
|
||||||
require("multi.threading.process")
|
|
||||||
require("multi.threading.step")
|
|
||||||
require("multi.threading.tstep")
|
|
||||||
require("multi.threading.updater")
|
|
||||||
|
|||||||
@ -21,21 +21,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
]]
|
]]
|
||||||
require("multi.all")
|
require("multi")
|
||||||
os.sleep=love.timer.sleep
|
os.sleep=love.timer.sleep
|
||||||
--~ function bin.load(file,s,r)
|
|
||||||
--~ content, size = love.filesystem.read(file)
|
|
||||||
--~ local temp=bin.new(content)
|
|
||||||
--~ temp.filepath=file
|
|
||||||
--~ return temp
|
|
||||||
--~ end
|
|
||||||
--~ function bin:tofile(filename)
|
|
||||||
--~ if not(filename) or self.Stream then return nil end
|
|
||||||
--~ love.filesystem.write(filename,self.data)
|
|
||||||
--~ end
|
|
||||||
--~ function bin.stream(file,l)
|
|
||||||
--~ error("Sorry streaming is not available when using love2d :(, I am looking for a solution though :)")
|
|
||||||
--~ end
|
|
||||||
function love.run()
|
function love.run()
|
||||||
if love.math then
|
if love.math then
|
||||||
love.math.setRandomSeed(os.time())
|
love.math.setRandomSeed(os.time())
|
||||||
|
|||||||
@ -45,7 +45,8 @@ function print(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
multi = {}
|
multi = {}
|
||||||
multi.Version={1,7,6}
|
multi.Version="1.8.2"
|
||||||
|
multi._VERSION="1.8.2"
|
||||||
multi.stage='stable'
|
multi.stage='stable'
|
||||||
multi.__index = multi
|
multi.__index = multi
|
||||||
multi.Mainloop={}
|
multi.Mainloop={}
|
||||||
@ -237,7 +238,7 @@ function multi:getChildren()
|
|||||||
return self.Mainloop
|
return self.Mainloop
|
||||||
end
|
end
|
||||||
function multi:getVersion()
|
function multi:getVersion()
|
||||||
return multi.Version[1].."."..multi.Version[2].."."..multi.Version[3]
|
return multi.Version
|
||||||
end
|
end
|
||||||
function multi:getPlatform()
|
function multi:getPlatform()
|
||||||
if love then
|
if love then
|
||||||
@ -248,6 +249,9 @@ function multi:getPlatform()
|
|||||||
return "lanes"
|
return "lanes"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return false
|
||||||
|
end
|
||||||
--Processor
|
--Processor
|
||||||
function multi:getError()
|
function multi:getError()
|
||||||
if self.error then
|
if self.error then
|
||||||
@ -417,7 +421,7 @@ function multi:protect()
|
|||||||
local status, err=pcall(Loop[_D].Act,Loop[_D])
|
local status, err=pcall(Loop[_D].Act,Loop[_D])
|
||||||
if err and not(Loop[_D].error) then
|
if err and not(Loop[_D].error) then
|
||||||
Loop[_D].error=err
|
Loop[_D].error=err
|
||||||
self.OnError:Fire(err,Loop[_D])
|
self.OnError:Fire(Loop[_D],err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1393,3 +1397,633 @@ function multi:newWatcher(namespace,name)
|
|||||||
print('Warning, invalid arguments! Nothing returned!')
|
print('Warning, invalid arguments! Nothing returned!')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- Threading stuff
|
||||||
|
thread={}
|
||||||
|
multi.GlobalVariables={}
|
||||||
|
if os.getOS()=="windows" then
|
||||||
|
thread.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
|
||||||
|
else
|
||||||
|
thread.__CORES=tonumber(io.popen("nproc --all"):read("*n"))
|
||||||
|
end
|
||||||
|
function thread.sleep(n)
|
||||||
|
coroutine.yield({"_sleep_",n or 0})
|
||||||
|
end
|
||||||
|
function thread.hold(n)
|
||||||
|
coroutine.yield({"_hold_",n or function() return true end})
|
||||||
|
end
|
||||||
|
function thread.skip(n)
|
||||||
|
coroutine.yield({"_skip_",n or 0})
|
||||||
|
end
|
||||||
|
function thread.kill()
|
||||||
|
coroutine.yield({"_kill_",":)"})
|
||||||
|
end
|
||||||
|
function thread.yeild()
|
||||||
|
coroutine.yield({"_sleep_",0})
|
||||||
|
end
|
||||||
|
function thread.getCores()
|
||||||
|
return thread.__CORES
|
||||||
|
end
|
||||||
|
function thread.set(name,val)
|
||||||
|
multi.GlobalVariables[name]=val
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function thread.get(name)
|
||||||
|
return multi.GlobalVariables[name]
|
||||||
|
end
|
||||||
|
function thread.waitFor(name)
|
||||||
|
thread.hold(function() return thread.get(name)~=nil end)
|
||||||
|
return thread.get(name)
|
||||||
|
end
|
||||||
|
function thread.testFor(name,val,sym)
|
||||||
|
thread.hold(function() return thread.get(name)~=nil end)
|
||||||
|
return thread.get(name)
|
||||||
|
end
|
||||||
|
function multi:newTBase(ins)
|
||||||
|
local c = {}
|
||||||
|
c.Active=true
|
||||||
|
c.func={}
|
||||||
|
c.ender={}
|
||||||
|
c.Id=0
|
||||||
|
c.PId=0
|
||||||
|
c.Parent=self
|
||||||
|
c.held=false
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThread(name,func)
|
||||||
|
local c={}
|
||||||
|
c.ref={}
|
||||||
|
c.Name=name
|
||||||
|
c.thread=coroutine.create(func)
|
||||||
|
c.sleep=1
|
||||||
|
c.Type="thread"
|
||||||
|
c.firstRunDone=false
|
||||||
|
c.timer=multi.scheduler:newTimer()
|
||||||
|
c.ref.Globals=self:linkDomain("Globals")
|
||||||
|
function c.ref:send(name,val)
|
||||||
|
ret=coroutine.yield({Name=name,Value=val})
|
||||||
|
self:syncGlobals(ret)
|
||||||
|
end
|
||||||
|
function c.ref:get(name)
|
||||||
|
return self.Globals[name]
|
||||||
|
end
|
||||||
|
function c.ref:kill()
|
||||||
|
err=coroutine.yield({"_kill_"})
|
||||||
|
if err then
|
||||||
|
error("Failed to kill a thread! Exiting...")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c.ref:sleep(n)
|
||||||
|
if type(n)=="function" then
|
||||||
|
ret=coroutine.yield({"_hold_",n})
|
||||||
|
self:syncGlobals(ret)
|
||||||
|
elseif type(n)=="number" then
|
||||||
|
n = tonumber(n) or 0
|
||||||
|
ret=coroutine.yield({"_sleep_",n})
|
||||||
|
self:syncGlobals(ret)
|
||||||
|
else
|
||||||
|
error("Invalid Type for sleep!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c.ref:syncGlobals(v)
|
||||||
|
self.Globals=v
|
||||||
|
end
|
||||||
|
table.insert(self:linkDomain("Threads"),c)
|
||||||
|
if not multi.scheduler:isActive() then
|
||||||
|
multi.scheduler:Resume()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
multi:setDomainName("Threads")
|
||||||
|
multi:setDomainName("Globals")
|
||||||
|
multi.scheduler=multi:newUpdater()
|
||||||
|
multi.scheduler.Type="scheduler"
|
||||||
|
function multi.scheduler:setStep(n)
|
||||||
|
self.skip=tonumber(n) or 24
|
||||||
|
end
|
||||||
|
multi.scheduler.skip=0
|
||||||
|
multi.scheduler.counter=0
|
||||||
|
multi.scheduler.Threads=multi:linkDomain("Threads")
|
||||||
|
multi.scheduler.Globals=multi:linkDomain("Globals")
|
||||||
|
multi.scheduler:OnUpdate(function(self)
|
||||||
|
self.counter=self.counter+1
|
||||||
|
for i=#self.Threads,1,-1 do
|
||||||
|
ret={}
|
||||||
|
if coroutine.status(self.Threads[i].thread)=="dead" then
|
||||||
|
table.remove(self.Threads,i)
|
||||||
|
else
|
||||||
|
if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
|
||||||
|
if self.Threads[i].firstRunDone==false then
|
||||||
|
self.Threads[i].firstRunDone=true
|
||||||
|
self.Threads[i].timer:Start()
|
||||||
|
_,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
|
||||||
|
else
|
||||||
|
_,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
|
||||||
|
end
|
||||||
|
if _==false then
|
||||||
|
self.Parent.OnError:Fire(self.Threads[i],ret)
|
||||||
|
print("Error in thread: <"..self.Threads[i].Name.."> "..ret)
|
||||||
|
end
|
||||||
|
if ret==true or ret==false then
|
||||||
|
print("Thread Ended!!!")
|
||||||
|
ret={}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ret then
|
||||||
|
if ret[1]=="_kill_" then
|
||||||
|
table.remove(self.Threads,i)
|
||||||
|
elseif ret[1]=="_sleep_" then
|
||||||
|
self.Threads[i].timer:Reset()
|
||||||
|
self.Threads[i].sleep=ret[2]
|
||||||
|
elseif ret[1]=="_skip_" then
|
||||||
|
self.Threads[i].timer:Reset()
|
||||||
|
self.Threads[i].sleep=math.huge
|
||||||
|
local event=multi:newEvent(function(evnt) return multi.scheduler.counter>=evnt.counter end)
|
||||||
|
event.link=self.Threads[i]
|
||||||
|
event.counter=self.counter+ret[2]
|
||||||
|
event:OnEvent(function(evnt)
|
||||||
|
evnt.link.sleep=0
|
||||||
|
end)
|
||||||
|
elseif ret[1]=="_hold_" then
|
||||||
|
self.Threads[i].timer:Reset()
|
||||||
|
self.Threads[i].sleep=math.huge
|
||||||
|
local event=multi:newEvent(ret[2])
|
||||||
|
event.link=self.Threads[i]
|
||||||
|
event:OnEvent(function(evnt)
|
||||||
|
evnt.link.sleep=0
|
||||||
|
end)
|
||||||
|
elseif ret.Name then
|
||||||
|
self.Globals[ret.Name]=ret.Value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
multi.scheduler:setStep()
|
||||||
|
multi.scheduler:Pause()
|
||||||
|
multi.OnError=multi:newConnection()
|
||||||
|
function multi:newThreadedAlarm(name,set)
|
||||||
|
local c=self:newTBase()
|
||||||
|
c.Type='alarmThread'
|
||||||
|
c.timer=self:newTimer()
|
||||||
|
c.set=set or 0
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.set)
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
self.timer:Resume()
|
||||||
|
end
|
||||||
|
function c:Reset(n)
|
||||||
|
if n then self.set=n end
|
||||||
|
self.rest=false
|
||||||
|
self.timer:Reset(n)
|
||||||
|
end
|
||||||
|
function c:OnRing(func)
|
||||||
|
table.insert(self.func,func)
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.timer:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
c.rest=false
|
||||||
|
c.updaterate=multi.Priority_Low -- skips
|
||||||
|
c.restRate=0 -- secs
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
if c.timer:Get()>=c.set then
|
||||||
|
c:Pause()
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
thread.skip(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedUpdater(name,skip)
|
||||||
|
local c=self:newTBase()
|
||||||
|
c.Type='updaterThread'
|
||||||
|
c.pos=1
|
||||||
|
c.skip=skip or 1
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
c.OnUpdate=self.OnMainConnect
|
||||||
|
c.rest=false
|
||||||
|
c.updaterate=0
|
||||||
|
c.restRate=.75
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](c)
|
||||||
|
end
|
||||||
|
c.pos=c.pos+1
|
||||||
|
thread.skip(c.skip)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedTStep(name,start,reset,count,set)
|
||||||
|
local c=self:newTBase()
|
||||||
|
local think=1
|
||||||
|
c.Type='tstepThread'
|
||||||
|
c.Priority=self.Priority_Low
|
||||||
|
c.start=start or 1
|
||||||
|
local reset = reset or math.huge
|
||||||
|
c.endAt=reset
|
||||||
|
c.pos=start or 1
|
||||||
|
c.skip=skip or 0
|
||||||
|
c.count=count or 1*think
|
||||||
|
c.funcE={}
|
||||||
|
c.timer=os.clock()
|
||||||
|
c.set=set or 1
|
||||||
|
c.funcS={}
|
||||||
|
function c:Update(start,reset,count,set)
|
||||||
|
self.start=start or self.start
|
||||||
|
self.pos=self.start
|
||||||
|
self.endAt=reset or self.endAt
|
||||||
|
self.set=set or self.set
|
||||||
|
self.count=count or self.count or 1
|
||||||
|
self.timer=os.clock()
|
||||||
|
self:Resume()
|
||||||
|
end
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.func)
|
||||||
|
m:addBlock(self.funcE)
|
||||||
|
m:addBlock(self.funcS)
|
||||||
|
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
function c:OnStart(func)
|
||||||
|
table.insert(self.funcS,func)
|
||||||
|
end
|
||||||
|
function c:OnStep(func)
|
||||||
|
table.insert(self.func,func)
|
||||||
|
end
|
||||||
|
function c:OnEnd(func)
|
||||||
|
table.insert(self.funcE,func)
|
||||||
|
end
|
||||||
|
function c:Break()
|
||||||
|
self.Active=nil
|
||||||
|
end
|
||||||
|
function c:Reset(n)
|
||||||
|
if n then self.set=n end
|
||||||
|
self.timer=os.clock()
|
||||||
|
self:Resume()
|
||||||
|
end
|
||||||
|
c.updaterate=0--multi.Priority_Low -- skips
|
||||||
|
c.restRate=0
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
if os.clock()-c.timer>=c.set then
|
||||||
|
c:Reset()
|
||||||
|
if c.pos==c.start then
|
||||||
|
for fe=1,#c.funcS do
|
||||||
|
c.funcS[fe](c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](c.pos,c)
|
||||||
|
end
|
||||||
|
c.pos=c.pos+c.count
|
||||||
|
if c.pos-c.count==c.endAt then
|
||||||
|
c:Pause()
|
||||||
|
for fe=1,#c.funcE do
|
||||||
|
c.funcE[fe](c)
|
||||||
|
end
|
||||||
|
c.pos=c.start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
thread.skip(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedTLoop(name,func,n)
|
||||||
|
local c=self:newTBase()
|
||||||
|
c.Type='tloopThread'
|
||||||
|
c.restN=n or 1
|
||||||
|
if func then
|
||||||
|
c.func={func}
|
||||||
|
end
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.func)
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
function c:OnLoop(func)
|
||||||
|
table.insert(self.func,func)
|
||||||
|
end
|
||||||
|
c.rest=false
|
||||||
|
c.updaterate=0
|
||||||
|
c.restRate=.75
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](c)
|
||||||
|
end
|
||||||
|
thread.sleep(c.restN) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedStep(name,start,reset,count,skip)
|
||||||
|
local c=self:newTBase()
|
||||||
|
local think=1
|
||||||
|
c.Type='stepThread'
|
||||||
|
c.pos=start or 1
|
||||||
|
c.endAt=reset or math.huge
|
||||||
|
c.skip=skip or 0
|
||||||
|
c.spos=0
|
||||||
|
c.count=count or 1*think
|
||||||
|
c.funcE={}
|
||||||
|
c.funcS={}
|
||||||
|
c.start=start or 1
|
||||||
|
if start~=nil and reset~=nil then
|
||||||
|
if start>reset then
|
||||||
|
think=-1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.func)
|
||||||
|
m:addBlock(self.funcE)
|
||||||
|
m:addBlock(self.funcS)
|
||||||
|
m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
c.Reset=c.Resume
|
||||||
|
function c:OnStart(func)
|
||||||
|
table.insert(self.funcS,func)
|
||||||
|
end
|
||||||
|
function c:OnStep(func)
|
||||||
|
table.insert(self.func,1,func)
|
||||||
|
end
|
||||||
|
function c:OnEnd(func)
|
||||||
|
table.insert(self.funcE,func)
|
||||||
|
end
|
||||||
|
function c:Break()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
function c:Update(start,reset,count,skip)
|
||||||
|
self.start=start or self.start
|
||||||
|
self.endAt=reset or self.endAt
|
||||||
|
self.skip=skip or self.skip
|
||||||
|
self.count=count or self.count
|
||||||
|
self:Resume()
|
||||||
|
end
|
||||||
|
c.updaterate=0
|
||||||
|
c.restRate=.1
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
ref:sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
if c~=nil then
|
||||||
|
if c.spos==0 then
|
||||||
|
if c.pos==c.start then
|
||||||
|
for fe=1,#c.funcS do
|
||||||
|
c.funcS[fe](c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](c.pos,c)
|
||||||
|
end
|
||||||
|
c.pos=c.pos+c.count
|
||||||
|
if c.pos-c.count==c.endAt then
|
||||||
|
c:Pause()
|
||||||
|
for fe=1,#c.funcE do
|
||||||
|
c.funcE[fe](c)
|
||||||
|
end
|
||||||
|
c.pos=c.start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.spos=c.spos+1
|
||||||
|
if c.spos>=c.skip then
|
||||||
|
c.spos=0
|
||||||
|
end
|
||||||
|
ref:sleep(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedProcess(name)
|
||||||
|
local c = {}
|
||||||
|
setmetatable(c, multi)
|
||||||
|
function c:newBase(ins)
|
||||||
|
local ct = {}
|
||||||
|
setmetatable(ct, self.Parent)
|
||||||
|
ct.Active=true
|
||||||
|
ct.func={}
|
||||||
|
ct.ender={}
|
||||||
|
ct.Id=0
|
||||||
|
ct.PId=0
|
||||||
|
ct.Act=function() end
|
||||||
|
ct.Parent=self
|
||||||
|
ct.held=false
|
||||||
|
ct.ref=self.ref
|
||||||
|
table.insert(self.Mainloop,ct)
|
||||||
|
return ct
|
||||||
|
end
|
||||||
|
c.Parent=self
|
||||||
|
c.Active=true
|
||||||
|
c.func={}
|
||||||
|
c.Id=0
|
||||||
|
c.Type='process'
|
||||||
|
c.Mainloop={}
|
||||||
|
c.Tasks={}
|
||||||
|
c.Tasks2={}
|
||||||
|
c.Garbage={}
|
||||||
|
c.Children={}
|
||||||
|
c.Paused={}
|
||||||
|
c.Active=true
|
||||||
|
c.Id=-1
|
||||||
|
c.Rest=0
|
||||||
|
c.updaterate=.01
|
||||||
|
c.restRate=.1
|
||||||
|
c.Jobs={}
|
||||||
|
c.queue={}
|
||||||
|
c.jobUS=2
|
||||||
|
c.rest=false
|
||||||
|
function c:getController()
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
function c:Start()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
function c:Remove()
|
||||||
|
self.ref:kill()
|
||||||
|
end
|
||||||
|
function c:kill()
|
||||||
|
err=coroutine.yield({"_kill_"})
|
||||||
|
if err then
|
||||||
|
error("Failed to kill a thread! Exiting...")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function c:sleep(n)
|
||||||
|
if type(n)=="function" then
|
||||||
|
ret=coroutine.yield({"_hold_",n})
|
||||||
|
elseif type(n)=="number" then
|
||||||
|
n = tonumber(n) or 0
|
||||||
|
ret=coroutine.yield({"_sleep_",n})
|
||||||
|
else
|
||||||
|
error("Invalid Type for sleep!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
c.hold=c.sleep
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
ref:Sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
c:uManager()
|
||||||
|
ref:sleep(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedLoop(name,func)
|
||||||
|
local c=self:newTBase()
|
||||||
|
c.Type='loopThread'
|
||||||
|
c.Start=os.clock()
|
||||||
|
if func then
|
||||||
|
c.func={func}
|
||||||
|
end
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.func)
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
function c:OnLoop(func)
|
||||||
|
table.insert(self.func,func)
|
||||||
|
end
|
||||||
|
c.rest=false
|
||||||
|
c.updaterate=0
|
||||||
|
c.restRate=.75
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
thread.sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
for i=1,#c.func do
|
||||||
|
c.func[i](os.clock()-self.Start,c)
|
||||||
|
end
|
||||||
|
thread.sleep(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newThreadedEvent(name,task)
|
||||||
|
local c=self:newTBase()
|
||||||
|
c.Type='eventThread'
|
||||||
|
c.Task=task or function() end
|
||||||
|
function c:OnEvent(func)
|
||||||
|
table.insert(self.func,func)
|
||||||
|
end
|
||||||
|
function c:tofile(path)
|
||||||
|
local m=bin.new()
|
||||||
|
m:addBlock(self.Type)
|
||||||
|
m:addBlock(self.Task)
|
||||||
|
m:addBlock(self.func)
|
||||||
|
m:addBlock(self.Active)
|
||||||
|
m:tofile(path)
|
||||||
|
end
|
||||||
|
function c:Resume()
|
||||||
|
self.rest=false
|
||||||
|
end
|
||||||
|
function c:Pause()
|
||||||
|
self.rest=true
|
||||||
|
end
|
||||||
|
c.rest=false
|
||||||
|
c.updaterate=0
|
||||||
|
c.restRate=1
|
||||||
|
multi:newThread(name,function(ref)
|
||||||
|
while true do
|
||||||
|
if c.rest then
|
||||||
|
ref:sleep(c.restRate) -- rest a bit more when a thread is paused
|
||||||
|
else
|
||||||
|
if c.Task(self) then
|
||||||
|
for _E=1,#c.func do
|
||||||
|
c.func[_E](c)
|
||||||
|
end
|
||||||
|
c:Pause()
|
||||||
|
end
|
||||||
|
ref:sleep(c.updaterate) -- lets rest a bit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
self:create(c)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|||||||
@ -30,8 +30,11 @@ function os.getOS()
|
|||||||
end
|
end
|
||||||
-- Step 1 get lanes
|
-- Step 1 get lanes
|
||||||
lanes=require("lanes").configure()
|
lanes=require("lanes").configure()
|
||||||
package.path="lua/?/init.lua;lua/?.lua;"..package.path
|
--~ package.path="lua/?/init.lua;lua/?.lua;"..package.path
|
||||||
require("multi.all") -- get it all and have it on all lanes
|
require("multi") -- get it all and have it on all lanes
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return true
|
||||||
|
end
|
||||||
local multi=multi
|
local multi=multi
|
||||||
-- Step 2 set up the linda objects
|
-- Step 2 set up the linda objects
|
||||||
local __GlobalLinda = lanes.linda() -- handles global stuff
|
local __GlobalLinda = lanes.linda() -- handles global stuff
|
||||||
@ -103,9 +106,10 @@ function multi:newSystemThread(name,func)
|
|||||||
local c={}
|
local c={}
|
||||||
local __self=c
|
local __self=c
|
||||||
c.name=name
|
c.name=name
|
||||||
|
c.Type="sthread"
|
||||||
c.thread=lanes.gen("*", func)()
|
c.thread=lanes.gen("*", func)()
|
||||||
function c:kill()
|
function c:kill()
|
||||||
self.status:Destroy()
|
--self.status:Destroy()
|
||||||
self.thread:cancel()
|
self.thread:cancel()
|
||||||
print("Thread: '"..self.name.."' has been stopped!")
|
print("Thread: '"..self.name.."' has been stopped!")
|
||||||
end
|
end
|
||||||
@ -114,7 +118,8 @@ function multi:newSystemThread(name,func)
|
|||||||
c.status:OnUpdate(function(self)
|
c.status:OnUpdate(function(self)
|
||||||
local v,err,t=self.link.thread:join(.001)
|
local v,err,t=self.link.thread:join(.001)
|
||||||
if err then
|
if err then
|
||||||
print("Error in thread: '"..self.link.name.."' <"..err..">")
|
multi.OnError:Fire(self.link,err)
|
||||||
|
print("Error in systemThread: '"..self.link.name.."' <"..err..">")
|
||||||
self:Destroy()
|
self:Destroy()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@ -124,7 +129,8 @@ print("Intergrated Lanes!")
|
|||||||
multi.intergration={} -- for module creators
|
multi.intergration={} -- for module creators
|
||||||
multi.intergration.GLOBAL=GLOBAL
|
multi.intergration.GLOBAL=GLOBAL
|
||||||
multi.intergration.THREAD=THREAD
|
multi.intergration.THREAD=THREAD
|
||||||
multi.intergration.lanes={} -- for module creators
|
multi.intergration.lanes={}
|
||||||
multi.intergration.lanes.GLOBAL=GLOBAL -- for module creators
|
multi.intergration.lanes.GLOBAL=GLOBAL -- for module creators
|
||||||
multi.intergration.lanes.THREAD=THREAD -- for module creators
|
multi.intergration.lanes.THREAD=THREAD -- for module creators
|
||||||
|
require("multi.intergration.shared.shared")
|
||||||
return {init=function() return GLOBAL,THREAD end}
|
return {init=function() return GLOBAL,THREAD end}
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
require("multi.compat.love2d")
|
require("multi.compat.love2d")
|
||||||
|
function multi:canSystemThread()
|
||||||
|
return true
|
||||||
|
end
|
||||||
multi.intergration={}
|
multi.intergration={}
|
||||||
multi.intergration.love2d={}
|
multi.intergration.love2d={}
|
||||||
multi.intergration.love2d.ThreadBase=[[
|
multi.intergration.love2d.ThreadBase=[[
|
||||||
|
__THREADNAME__=({...})[1]
|
||||||
require("love.filesystem")
|
require("love.filesystem")
|
||||||
require("love.system")
|
require("love.system")
|
||||||
require("love.timer")
|
require("love.timer")
|
||||||
@ -9,9 +13,11 @@ require("multi.all")
|
|||||||
GLOBAL={}
|
GLOBAL={}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(GLOBAL,{
|
||||||
__index=function(t,k)
|
__index=function(t,k)
|
||||||
|
__sync__()
|
||||||
return __proxy__[k]
|
return __proxy__[k]
|
||||||
end,
|
end,
|
||||||
__newindex=function(t,k,v)
|
__newindex=function(t,k,v)
|
||||||
|
__sync__()
|
||||||
__proxy__[k]=v
|
__proxy__[k]=v
|
||||||
if type(v)=="userdata" then
|
if type(v)=="userdata" then
|
||||||
__MainChan__:push(v)
|
__MainChan__:push(v)
|
||||||
@ -20,6 +26,23 @@ setmetatable(GLOBAL,{
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
function __sync__()
|
||||||
|
local data=__mythread__:pop()
|
||||||
|
while data do
|
||||||
|
if type(data)=="string" then
|
||||||
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
|
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
||||||
|
error("Thread: "..__THREADNAME__.." has been stopped!")
|
||||||
|
end
|
||||||
|
if cmd=="SYNC" then
|
||||||
|
__proxy__[name]=resolveType(tp,d)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
__proxy__[name]=data
|
||||||
|
end
|
||||||
|
data=__mythread__:pop()
|
||||||
|
end
|
||||||
|
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
|
||||||
@ -43,6 +66,8 @@ function ToStr(val, name, skipnewlines, depth)
|
|||||||
tmp = tmp .. string.format("%q", val)
|
tmp = tmp .. string.format("%q", val)
|
||||||
elseif type(val) == "boolean" then
|
elseif type(val) == "boolean" then
|
||||||
tmp = tmp .. (val and "true" or "false")
|
tmp = tmp .. (val and "true" or "false")
|
||||||
|
elseif type(val) == "function" then
|
||||||
|
tmp = tmp .. "loadDump([===["..dump(val).."]===])"
|
||||||
else
|
else
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
||||||
end
|
end
|
||||||
@ -57,6 +82,8 @@ function resolveType(tp,d)
|
|||||||
return loadDump(d)
|
return loadDump(d)
|
||||||
elseif tp=="table" then
|
elseif tp=="table" then
|
||||||
return loadstring("return "..d)()
|
return loadstring("return "..d)()
|
||||||
|
elseif tp=="nil" then
|
||||||
|
return nil
|
||||||
else
|
else
|
||||||
return d
|
return d
|
||||||
end
|
end
|
||||||
@ -67,7 +94,7 @@ function resolveData(v)
|
|||||||
data=ToStr(v)
|
data=ToStr(v)
|
||||||
elseif type(v)=="function" then
|
elseif type(v)=="function" then
|
||||||
data=dump(v)
|
data=dump(v)
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" then
|
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
||||||
data=tostring(v)
|
data=tostring(v)
|
||||||
end
|
end
|
||||||
return data
|
return data
|
||||||
@ -77,7 +104,7 @@ local function randomString(n)
|
|||||||
local c=os.clock()
|
local c=os.clock()
|
||||||
local a=0
|
local a=0
|
||||||
while os.clock()<c+.1 do
|
while os.clock()<c+.1 do
|
||||||
a=a+1
|
a=a+1 -- each cpu has a different load... Doing this allows up to make unique seeds for the random string
|
||||||
end
|
end
|
||||||
math.randomseed(a)
|
math.randomseed(a)
|
||||||
local str = ''
|
local str = ''
|
||||||
@ -113,22 +140,7 @@ function sThread.get(name)
|
|||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.waitFor(name)
|
function sThread.waitFor(name)
|
||||||
--print("Waiting:",__mythreadname__)
|
repeat __sync__() until GLOBAL[name]
|
||||||
local function wait()
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until GLOBAL[name]
|
|
||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.getCores()
|
function sThread.getCores()
|
||||||
@ -138,21 +150,7 @@ function sThread.sleep(n)
|
|||||||
love.timer.sleep(n)
|
love.timer.sleep(n)
|
||||||
end
|
end
|
||||||
function sThread.hold(n)
|
function sThread.hold(n)
|
||||||
local function wait()
|
repeat __sync__() until n()
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until n()
|
|
||||||
end
|
end
|
||||||
updater=multi:newUpdater()
|
updater=multi:newUpdater()
|
||||||
updater:OnUpdate(function(self)
|
updater:OnUpdate(function(self)
|
||||||
@ -160,6 +158,9 @@ updater:OnUpdate(function(self)
|
|||||||
while data do
|
while data do
|
||||||
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"..__THREADNAME__.."__" then
|
||||||
|
error("Thread: "..__THREADNAME__.." has been stopped!")
|
||||||
|
end
|
||||||
if cmd=="SYNC" then
|
if cmd=="SYNC" then
|
||||||
__proxy__[name]=resolveType(tp,d)
|
__proxy__[name]=resolveType(tp,d)
|
||||||
end
|
end
|
||||||
@ -214,6 +215,8 @@ function ToStr(val, name, skipnewlines, depth)
|
|||||||
tmp = tmp .. string.format("%q", val)
|
tmp = tmp .. string.format("%q", val)
|
||||||
elseif type(val) == "boolean" then
|
elseif type(val) == "boolean" then
|
||||||
tmp = tmp .. (val and "true" or "false")
|
tmp = tmp .. (val and "true" or "false")
|
||||||
|
elseif type(val) == "function" then
|
||||||
|
tmp = tmp .. "loadDump([===["..dump(val).."]===])"
|
||||||
else
|
else
|
||||||
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
|
||||||
end
|
end
|
||||||
@ -228,6 +231,8 @@ function resolveType(tp,d)
|
|||||||
return loadDump(d)
|
return loadDump(d)
|
||||||
elseif tp=="table" then
|
elseif tp=="table" then
|
||||||
return loadstring("return "..d)()
|
return loadstring("return "..d)()
|
||||||
|
elseif tp=="nil" then
|
||||||
|
return nil
|
||||||
else
|
else
|
||||||
return d
|
return d
|
||||||
end
|
end
|
||||||
@ -238,7 +243,7 @@ function resolveData(v)
|
|||||||
data=ToStr(v)
|
data=ToStr(v)
|
||||||
elseif type(v)=="function" then
|
elseif type(v)=="function" then
|
||||||
data=dump(v)
|
data=dump(v)
|
||||||
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" then
|
elseif type(v)=="string" or type(v)=="number" or type(v)=="bool" or type(v)=="nil" then
|
||||||
data=tostring(v)
|
data=tostring(v)
|
||||||
end
|
end
|
||||||
return data
|
return data
|
||||||
@ -257,15 +262,28 @@ function dump(func)
|
|||||||
end
|
end
|
||||||
return table.concat(code)
|
return table.concat(code)
|
||||||
end
|
end
|
||||||
|
local function 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:newSystemThread(name,func) -- the main method
|
function multi:newSystemThread(name,func) -- the main method
|
||||||
local c={}
|
local c={}
|
||||||
c.name=name
|
c.name=name
|
||||||
|
c.ID=c.name.."<ID|"..randomString(8)..">"
|
||||||
c.thread=love.thread.newThread(multi.intergration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
c.thread=love.thread.newThread(multi.intergration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
||||||
c.thread:start()
|
c.thread:start(c.ID)
|
||||||
|
function c:kill()
|
||||||
|
multi.intergration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__"
|
||||||
|
end
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
function love.threaderror( thread, errorstr )
|
function love.threaderror( thread, errorstr )
|
||||||
print("Error in "..tostring(thread)..": "..errorstr)
|
multi.OnError:Fire(thread,errorstr)
|
||||||
|
print("Error in systemThread: "..tostring(thread)..": "..errorstr)
|
||||||
end
|
end
|
||||||
local THREAD={}
|
local THREAD={}
|
||||||
function THREAD.set(name,val)
|
function THREAD.set(name,val)
|
||||||
@ -327,6 +345,7 @@ updater:OnUpdate(function(self)
|
|||||||
data=multi.intergration.love2d.mainChannel:pop()
|
data=multi.intergration.love2d.mainChannel:pop()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
require("multi.intergration.shared.shared")
|
||||||
print("Intergrated Love2d!")
|
print("Intergrated Love2d!")
|
||||||
return {
|
return {
|
||||||
init=function(t)
|
init=function(t)
|
||||||
|
|||||||
@ -0,0 +1,176 @@
|
|||||||
|
--[[
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Ryan Ward
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
]]
|
||||||
|
function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a channel on both ends
|
||||||
|
local c={} -- where we will store our object
|
||||||
|
c.name=name -- set the name this is important for the love2d side
|
||||||
|
if love then -- check love
|
||||||
|
if love.thread then -- make sure we can use the threading module
|
||||||
|
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(v)
|
||||||
|
end
|
||||||
|
function self:pop() -- pop from the channel
|
||||||
|
return self.chan:pop()
|
||||||
|
end
|
||||||
|
GLOBAL[self.name]=self -- send the object to the thread through the global interface
|
||||||
|
return self -- return the object
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module
|
||||||
|
end
|
||||||
|
else
|
||||||
|
c.linda=lanes.linda() -- lanes is a bit eaiser, create the linda on the main thread
|
||||||
|
function c:push(v) -- push to the queue
|
||||||
|
self.linda:send("Q",v)
|
||||||
|
end
|
||||||
|
function c:pop() -- pop the queue
|
||||||
|
return ({self.linda:receive(0,"Q")})[2]
|
||||||
|
end
|
||||||
|
function c:init() -- mimic the feature that love2d requires, so code can be consistent
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
multi.intergration.GLOBAL[name]=c -- send the object to the thread through the global interface
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:systemThreadedBenchmark(n,p)
|
||||||
|
n=n or 1
|
||||||
|
local cores=multi.intergration.THREAD.getCores()
|
||||||
|
local queue=multi:newSystemThreadedQueue("QUEUE")
|
||||||
|
multi.intergration.GLOBAL["__SYSTEMBENCHMARK__"]=n
|
||||||
|
local sThread=multi.intergration.THREAD
|
||||||
|
local GLOBAL=multi.intergration.GLOBAL
|
||||||
|
for i=1,cores do
|
||||||
|
multi:newSystemThread("STHREAD_BENCH",function()
|
||||||
|
require("multi")
|
||||||
|
if multi:getPlatform()=="love2d" then
|
||||||
|
GLOBAL=_G.GLOBAL
|
||||||
|
sThread=_G.sThread
|
||||||
|
end -- we cannot have upvalues... in love2d globals not locals must be used
|
||||||
|
queue=sThread.waitFor("QUEUE"):init() -- always wait for when looking for a variable at the start of the thread!
|
||||||
|
multi:benchMark(sThread.waitFor("__SYSTEMBENCHMARK__")):OnBench(function(self,count)
|
||||||
|
queue:push(count)
|
||||||
|
multi:Stop()
|
||||||
|
end)
|
||||||
|
multi:mainloop()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
local c={}
|
||||||
|
c.tt=function() end
|
||||||
|
c.p=p
|
||||||
|
function c:OnBench(func)
|
||||||
|
self.tt=func
|
||||||
|
end
|
||||||
|
multi:newThread("THREAD_BENCH",function()
|
||||||
|
thread.sleep(n+.1)
|
||||||
|
GLOBAL["QUEUE"]=nil -- time to clean up
|
||||||
|
local num=0
|
||||||
|
data=queue:pop()
|
||||||
|
while data do
|
||||||
|
num=num+data
|
||||||
|
data=queue:pop()
|
||||||
|
end
|
||||||
|
if p then
|
||||||
|
print(tostring(p)..num)
|
||||||
|
end
|
||||||
|
c.tt(c,num)
|
||||||
|
end)
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
function multi:newSystemThreadedTable(name)
|
||||||
|
local c={} -- where we will store our object
|
||||||
|
c.name=name -- set the name this is important for the love2d side
|
||||||
|
if love then -- check love
|
||||||
|
if love.thread then -- make sure we can use the threading module
|
||||||
|
function c:init() -- create an init function so we can mimic on bith love2d and lanes
|
||||||
|
self.tab={}
|
||||||
|
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
|
||||||
|
function self:waitFor(name) -- pop from the channel
|
||||||
|
repeat self:sync() until self[name]
|
||||||
|
return self[name]
|
||||||
|
end
|
||||||
|
function self:sync()
|
||||||
|
local data=self.chan:pop()
|
||||||
|
while data do
|
||||||
|
if type(data)=="string" then
|
||||||
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
|
if cmd=="SYNC" then
|
||||||
|
self.tab[name]=resolveType(tp,d) -- this is defined in the loveManager.lua file
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.tab[name]=data
|
||||||
|
end
|
||||||
|
data=self.chan:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
setmetatable(self,{
|
||||||
|
__index=function(t,k)
|
||||||
|
self:sync()
|
||||||
|
return self.tab[k]
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
self:sync()
|
||||||
|
self.tab[k]=v
|
||||||
|
if type(v)=="userdata" then
|
||||||
|
self.chan:push(v)
|
||||||
|
else
|
||||||
|
self.chan:push("SYNC "..type(v).." "..k.." "..resolveData(v)) -- this is defined in the loveManager.lua file
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
GLOBAL[self.name]=self -- send the object to the thread through the global interface
|
||||||
|
return self -- return the object
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module
|
||||||
|
end
|
||||||
|
else
|
||||||
|
c.linda=lanes.linda() -- lanes is a bit eaiser, create the linda on the main thread
|
||||||
|
function c:waitFor(name)
|
||||||
|
while self[name]==nil do
|
||||||
|
-- Waiting
|
||||||
|
end
|
||||||
|
return self[name]
|
||||||
|
end
|
||||||
|
function c:sync()
|
||||||
|
return -- just so we match the love2d side
|
||||||
|
end
|
||||||
|
function c:init() -- set the metatable
|
||||||
|
setmetatable(self,{
|
||||||
|
__index=function(t,k)
|
||||||
|
return self.linda:get(k)
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
self.linda:set(k,v)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
multi.intergration.GLOBAL[name]=c -- send the object to the thread through the global interface
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
@ -23,19 +23,6 @@ SOFTWARE.
|
|||||||
]]
|
]]
|
||||||
require("multi")
|
require("multi")
|
||||||
os.sleep=love.timer.sleep
|
os.sleep=love.timer.sleep
|
||||||
--~ function bin.load(file,s,r)
|
|
||||||
--~ content, size = love.filesystem.read(file)
|
|
||||||
--~ local temp=bin.new(content)
|
|
||||||
--~ temp.filepath=file
|
|
||||||
--~ return temp
|
|
||||||
--~ end
|
|
||||||
--~ function bin:tofile(filename)
|
|
||||||
--~ if not(filename) or self.Stream then return nil end
|
|
||||||
--~ love.filesystem.write(filename,self.data)
|
|
||||||
--~ end
|
|
||||||
--~ function bin.stream(file,l)
|
|
||||||
--~ error("Sorry streaming is not available when using love2d :(, I am looking for a solution though :)")
|
|
||||||
--~ end
|
|
||||||
function love.run()
|
function love.run()
|
||||||
if love.math then
|
if love.math then
|
||||||
love.math.setRandomSeed(os.time())
|
love.math.setRandomSeed(os.time())
|
||||||
|
|||||||
@ -45,7 +45,8 @@ function print(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
multi = {}
|
multi = {}
|
||||||
multi.Version={1,8,1}
|
multi.Version="1.8.2"
|
||||||
|
multi._VERSION="1.8.2"
|
||||||
multi.stage='stable'
|
multi.stage='stable'
|
||||||
multi.__index = multi
|
multi.__index = multi
|
||||||
multi.Mainloop={}
|
multi.Mainloop={}
|
||||||
@ -237,7 +238,7 @@ function multi:getChildren()
|
|||||||
return self.Mainloop
|
return self.Mainloop
|
||||||
end
|
end
|
||||||
function multi:getVersion()
|
function multi:getVersion()
|
||||||
return multi.Version[1].."."..multi.Version[2].."."..multi.Version[3]
|
return multi.Version
|
||||||
end
|
end
|
||||||
function multi:getPlatform()
|
function multi:getPlatform()
|
||||||
if love then
|
if love then
|
||||||
|
|||||||
@ -13,9 +13,11 @@ require("multi.all")
|
|||||||
GLOBAL={}
|
GLOBAL={}
|
||||||
setmetatable(GLOBAL,{
|
setmetatable(GLOBAL,{
|
||||||
__index=function(t,k)
|
__index=function(t,k)
|
||||||
|
__sync__()
|
||||||
return __proxy__[k]
|
return __proxy__[k]
|
||||||
end,
|
end,
|
||||||
__newindex=function(t,k,v)
|
__newindex=function(t,k,v)
|
||||||
|
__sync__()
|
||||||
__proxy__[k]=v
|
__proxy__[k]=v
|
||||||
if type(v)=="userdata" then
|
if type(v)=="userdata" then
|
||||||
__MainChan__:push(v)
|
__MainChan__:push(v)
|
||||||
@ -24,6 +26,23 @@ setmetatable(GLOBAL,{
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
function __sync__()
|
||||||
|
local data=__mythread__:pop()
|
||||||
|
while data do
|
||||||
|
if type(data)=="string" then
|
||||||
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
|
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
||||||
|
error("Thread: "..__THREADNAME__.." has been stopped!")
|
||||||
|
end
|
||||||
|
if cmd=="SYNC" then
|
||||||
|
__proxy__[name]=resolveType(tp,d)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
__proxy__[name]=data
|
||||||
|
end
|
||||||
|
data=__mythread__:pop()
|
||||||
|
end
|
||||||
|
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
|
||||||
@ -121,25 +140,7 @@ function sThread.get(name)
|
|||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.waitFor(name)
|
function sThread.waitFor(name)
|
||||||
--print("Waiting:",__mythreadname__)
|
repeat __sync__() until GLOBAL[name]
|
||||||
local function wait()
|
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
|
||||||
error("Thread: "..__THREADNAME__.." has been stopped!")
|
|
||||||
end
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until GLOBAL[name]
|
|
||||||
return GLOBAL[name]
|
return GLOBAL[name]
|
||||||
end
|
end
|
||||||
function sThread.getCores()
|
function sThread.getCores()
|
||||||
@ -149,24 +150,7 @@ function sThread.sleep(n)
|
|||||||
love.timer.sleep(n)
|
love.timer.sleep(n)
|
||||||
end
|
end
|
||||||
function sThread.hold(n)
|
function sThread.hold(n)
|
||||||
local function wait()
|
repeat __sync__() until n()
|
||||||
local data=__mythread__:pop()
|
|
||||||
while data do
|
|
||||||
if type(data)=="string" then
|
|
||||||
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
|
||||||
if name=="__DIEPLZ"..__THREADNAME__.."__" then
|
|
||||||
error("Thread: "..__THREADNAME__.." has been stopped!")
|
|
||||||
end
|
|
||||||
if cmd=="SYNC" then
|
|
||||||
__proxy__[name]=resolveType(tp,d)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
__proxy__[name]=data
|
|
||||||
end
|
|
||||||
data=__mythread__:pop()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
repeat wait() until n()
|
|
||||||
end
|
end
|
||||||
updater=multi:newUpdater()
|
updater=multi:newUpdater()
|
||||||
updater:OnUpdate(function(self)
|
updater:OnUpdate(function(self)
|
||||||
|
|||||||
@ -100,3 +100,77 @@ function multi:systemThreadedBenchmark(n,p)
|
|||||||
end)
|
end)
|
||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
function multi:newSystemThreadedTable(name)
|
||||||
|
local c={} -- where we will store our object
|
||||||
|
c.name=name -- set the name this is important for the love2d side
|
||||||
|
if love then -- check love
|
||||||
|
if love.thread then -- make sure we can use the threading module
|
||||||
|
function c:init() -- create an init function so we can mimic on bith love2d and lanes
|
||||||
|
self.tab={}
|
||||||
|
self.chan=love.thread.getChannel(self.name) -- create channel by the name self.name
|
||||||
|
function self:waitFor(name) -- pop from the channel
|
||||||
|
repeat self:sync() until self[name]
|
||||||
|
return self[name]
|
||||||
|
end
|
||||||
|
function self:sync()
|
||||||
|
local data=self.chan:pop()
|
||||||
|
while data do
|
||||||
|
if type(data)=="string" then
|
||||||
|
local cmd,tp,name,d=data:match("(%S-) (%S-) (%S-) (.+)")
|
||||||
|
if cmd=="SYNC" then
|
||||||
|
self.tab[name]=resolveType(tp,d) -- this is defined in the loveManager.lua file
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.tab[name]=data
|
||||||
|
end
|
||||||
|
data=self.chan:pop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
setmetatable(self,{
|
||||||
|
__index=function(t,k)
|
||||||
|
self:sync()
|
||||||
|
return self.tab[k]
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
self:sync()
|
||||||
|
self.tab[k]=v
|
||||||
|
if type(v)=="userdata" then
|
||||||
|
self.chan:push(v)
|
||||||
|
else
|
||||||
|
self.chan:push("SYNC "..type(v).." "..k.." "..resolveData(v)) -- this is defined in the loveManager.lua file
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
GLOBAL[self.name]=self -- send the object to the thread through the global interface
|
||||||
|
return self -- return the object
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
error("Make sure you required the love.thread module!") -- tell the user if he/she didn't require said module
|
||||||
|
end
|
||||||
|
else
|
||||||
|
c.linda=lanes.linda() -- lanes is a bit eaiser, create the linda on the main thread
|
||||||
|
function c:waitFor(name)
|
||||||
|
while self[name]==nil do
|
||||||
|
-- Waiting
|
||||||
|
end
|
||||||
|
return self[name]
|
||||||
|
end
|
||||||
|
function c:sync()
|
||||||
|
return -- just so we match the love2d side
|
||||||
|
end
|
||||||
|
function c:init() -- set the metatable
|
||||||
|
setmetatable(self,{
|
||||||
|
__index=function(t,k)
|
||||||
|
return self.linda:get(k)
|
||||||
|
end,
|
||||||
|
__newindex=function(t,k,v)
|
||||||
|
self.linda:set(k,v)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
multi.intergration.GLOBAL[name]=c -- send the object to the thread through the global interface
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user