Some major changes to loveManager

Still working on version 14.0,.0
This commit is contained in:
Ryan Ward 2019-12-16 20:15:34 -05:00
parent c2488ed5ce
commit ae9f76d938
12 changed files with 727 additions and 171 deletions

View File

@ -11,7 +11,7 @@ Added:
-- tobj.OnDeath(self,status,returns[...]) -- This is a connection that passes a reference to the self, the status, whether or not the thread ended or was killed, and the returns of the thread.
-- tobj.OnError(self,error) -- returns a reference to self and the error as a string
-- **Limitations:** only 7 returns are possible! This was done because creating and destroying table objects are slow. Instead I capture the return values from coroutine.resume into local variables and only allowed it to collect 6 max.
- thread.run(function) -- Can only be used within a thread, creates another thread that can do work, but automatically returns whatever from the run function
- thread.run(function) -- Can only be used within a thread, creates another thread that can do work, but automatically returns whatever from the run function -- Use thread newfunctions for a more powerful version of thread.run()
- thread:newFunction(FUNCTION; func)
-- returns a function that gives you the option to wait or connect to the returns of the function.
-- func().wait() -- only works when within a coroutine based thread
@ -20,13 +20,58 @@ Added:
-- If the created function encounters an error, it will return nil, the error message!
- special variable multi.NIL was added to allow error handling in threaded functions.
-- multi.NIL can be used in to force a nil value when using thread.hold()
- All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features
- All functions created in the root of a thread are now converted to threaded functions, which allow for wait and connect features. **Note:** these functions are local to the function! And are only converted if they aren't set as local! Otherwise the function
thread newFunction
```lua
func=thread:newFunction(function(...)
print("Function running...")
thread.sleep(1)
return {1,2,3},"done"
end)
multi:newThread("Test",function()
func().connect(function(...)
print(...)
end)
end)
----OUTPUT----
> Function running...
> table: 0x008cf340 done nil nil nil nil nil
```
thread newFunction using auto convert
```lua
package.path = "./?/init.lua;" .. package.path
multi, thread = require("multi").init()
a=5
multi:newThread("Test",function()
function hmm() -- Auto converted into a threaded function
return "Hello!",2
end
print(a)
a=10
print(hmm().wait())
end)
multi:newAlarm(3):OnRing(function()
print(a)
end)
print(hmm)
multi:mainloop()
-----OUTPUT-----
> nil
> 5
> Hello! 2 nil nil nil nil nil -- The way I manage function returns is by allocating them to predefined locals. Because I pass these values regardless they technically get passed even when they are nil. This choice was made to keep the creation of tables to capture arguments then using unpack to pass them on when processing is done
> 10
```
Fixed:
- Connections had a preformance issue where they would create a non function when using connection.getConnection() of a non existing label.
- An internal mismanagement of the treads scheduler was fixed. Now it should be quicker and free of bugs
- Thread error management is the integrations was not properly implemented. This is now fixed
-
Removed:
- multi:newWatcher() -- No real use
- multi:newCustomObject() -- No real use
Changed:
- Ties in to the new function that has been added multi.init()
@ -45,7 +90,7 @@ local nGLOBAL, nTHREAD = require("multi.intergration.networkManager).inti()
Note: You can mix and match integrations together. You can create systemthreads within network threads, and you can also create cotoutine based threads within bothe network and system threads. This gives you quite a bit of flexibility to create something awesome.
Going forward:
- Sterlization is still being worked on. I was planning of having a way to save state of multi objects and such, but that isn't possible without knowing how your code is strutured or if it is even made to handle something like that. So I decided on giving a tostirng/tofile method for each multi object as well as a fromstring/fromfile method for use. This is technically in the code already, but not documented. It has actually been in the code for a while, but its not done just yet and I want to make it perfect before sending it out.
- Do not expect anything new from the next update. I have a bunch of bugs to iron out. Most pertainint to network and system threading. Maybe
Update 13.1.0 Bug fixes and features added
-------------

View File

@ -0,0 +1,39 @@
--local test = love.newByteData(string.rep("\0",16)
local ffi = require("ffi")
local scratchpad = {}
local mt = {
__index = function(t, k)
if type(k)=="string" then
local a, b = k:match("(%d+):(%d+)")
return t:read(tonumber(a),tonumber(b))
elseif type(k)=="number" then
return t:read(k,1)
end
end,
__newindex = function(t, k, v)
t:write(v,k)
end
}
function scratchpad:new(data, size, rep)
local c = {}
local pad
if type(data)=="string" then
pad = love.data.newByteData(data or string.rep(rep or "\0",size or 16))
elseif data:type()=="ByteData" then
pad = bytedata
end
local ptr = ffi.cast("unsigned char*",pad:getPointer())
local size = pad:getSize()
function c:write(data, loc, len)
if loc+(len or #data)>size then
error("Attpemting to write data outside the bounds of data byte array!")
end
ffi.copy(ptr+(loc or 0), data, len or #data)
end
function c:read(loc, len)
return ffi.string(ptr+(loc or 0), len or size)
end
setmetatable(c,mt)
return c
end
return scratchpad

View File

@ -952,27 +952,6 @@ function multi.nextStep(func)
end
multi.OnPreLoad=multi:newConnection()
--Core Actors
function multi:newCustomObject(objRef,isActor)
local c={}
if isActor then
c=self:newBase()
if type(objRef)=='table' then
table.merge(c,objRef)
end
if not c.Act then
function c:Act()
-- Empty function
end
end
else
c=objRef or {}
end
if not c.Type then
c.Type='coustomObject'
end
self:create(c)
return c
end
function multi:newEvent(task)
local c=self:newBase()
c.Type='event'
@ -1434,40 +1413,6 @@ function multi:newTimeStamper()
self:create(c)
return c
end
function multi:newWatcher(namespace,name)
local function WatcherObj(ns,n)
if self.Type=='queue' then
multi.print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
self=multi
end
local c=self:newBase()
c.Type='watcher'
c.ns=ns
c.n=n
c.cv=ns[n]
function c:OnValueChanged(func)
table.insert(self.func,func)
return self
end
function c:Act()
if self.cv~=self.ns[self.n] then
for i=1,#self.func do
self.func[i](self,self.cv,self.ns[self.n])
end
self.cv=self.ns[self.n]
end
end
self:create(c)
return c
end
if type(namespace)~='table' and type(namespace)=='string' then
return WatcherObj(_G,namespace)
elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
return WatcherObj(namespace,name)
else
multi.print('Warning, invalid arguments! Nothing returned!')
end
end
-- Threading stuff
multi.GlobalVariables={}
if os.getOS()=="windows" then
@ -1536,14 +1481,10 @@ function thread.waitFor(name)
return thread.get(name)
end
function thread:newFunction(func)
local c = {}
local c = {Type = "tfunc"}
c.__call = function(self,...)
local rets, err
local t = multi:newThread("TempThread",func)
t.OnDeath(function(self,status,...) rets = {...} end)
t.OnError(function(self,e) err = e end)
return {
wait = function()
local function wait()
return thread.hold(function()
if err then
return multi.NIL, err
@ -1551,12 +1492,22 @@ function thread:newFunction(func)
return unpack(rets)
end
end)
end,
end
local t = multi:newThread("TempThread",func,...)
t.OnDeath(function(self,status,...) rets = {...} end)
t.OnError(function(self,e) err = e end)
--if thread.isThread() then
-- return wait()
--else
return {
isTFunc = true,
wait = wait,
connect = function(f)
t.OnDeath(function(self,status,...) f(...) end)
t.OnError(function(self,err) f(self, err) end)
end
}
--end
end
setmetatable(c,c)
return c
@ -1600,24 +1551,26 @@ local threadCount = 0
local threadid = 0
thread.__threads = {}
local threads = thread.__threads
function multi:newThread(name,func)
local Gref = _G
function multi:newThread(name,func,...)
local func = func or name
if type(name) == "function" then
name = "Thread#"..threadCount
end
local env = {}
setmetatable(env,{
__index = _G,
__index = Gref,
__newindex = function(t,k,v)
if type(v)=="function" then
rawset(t,k,thread:newFunction(v))
else
rawset(t,k,v)
Gref[k]=v
end
end
})
setfenv(func,env)
local c={}
c.startArgs = {...}
c.ref={}
c.Name=name
c.thread=coroutine.create(func)
@ -1741,7 +1694,7 @@ function multi.initThreads()
multi.scheduler:OnLoop(function(self)
for i=#threads,1,-1 do
if not threads[i].__started then
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread)
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,unpack(threads[i].startArgs))
threads[i].__started = true
helper(i)
end

View File

@ -73,7 +73,70 @@ function THREAD.get(name)
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'}
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

View File

@ -309,7 +309,70 @@ function dump(func)
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'}
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

View File

@ -0,0 +1,160 @@
local multi, thread = require("multi").init()
local status = require("multi.integration.loveManager.status")
local pad = require("multi.integration.loveManager.scratchpad")
GLOBAL = multi.integration.GLOBAL
THREAD = multi.integration.THREAD
function multi:newSystemThreadedQueue(name)
local c = {}
c.Name = name
local fRef = {"func",nil}
function c:init()
local q = {}
q.chan = love.thread.getChannel(self.Name)
function q:push(dat)
if type(dat) == "function" then
fRef[2] = THREAD.dump(dat)
self.chan:push(fRef)
return
else
self.chan:push(dat)
end
end
function q:pop()
local dat = self.chan:pop()
if type(dat)=="table" and dat[1]=="func" then
return THREAD.loadDump(dat[2])
else
return dat
end
end
function q:peek()
local dat = self.chan:peek()
if type(dat)=="table" and dat[1]=="func" then
return THREAD.loadDump(dat[2])
else
return dat
end
end
return q
end
THREAD.package(name,c)
return c
end
function multi:newSystemThreadedTable(name)
local c = {}
c.name = name
function c:init()
return THREAD.createTable(self.name)
end
THREAD.package(name,c)
return c
end
local jqc = 1
function multi:newSystemThreadedJobQueue(n)
local c = {}
c.cores = n or THREAD.getCores()
c.registerQueue = {}
c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table")
c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue")
c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn")
c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
c.id = 0
c.OnJobCompleted = multi:newConnection()
c._bytedata = love.data.newByteData(string.rep(status.BUSY,c.cores))
c.bytedata = pad:new(c._bytedata)
local allfunc = 0
function c:doToAll(func)
self.bytedata:write(string.rep(status.BUSY,c.cores)) -- set all variables to busy
local f = THREAD.dump(func)
for i = 1, self.cores do
self.queueAll:push({allfunc,f})
end
allfunc = allfunc + 1
end
function c:registerFunction(name,func)
if self.funcs[name] then
error("A function by the name "..name.." has already been registered!")
end
self.bytedata:write(string.rep(status.BUSY,c.cores)) -- set all variables to busy
self.funcs[name] = func
end
function c:pushJob(name,...)
self.id = self.id + 1
self.queue:push{name,self.id,...}
return self.id
end
multi:newThread("jobManager",function()
while true do
thread.yield()
local dat = c.queueReturn:pop()
if dat then
print(dat)
c.OnJobCompleted:Fire(unpack(dat))
end
end
end)
for i=1,c.cores do
multi:newSystemThread("JobQueue_"..jqc.."_worker_"..i,function(jqc)
local multi, thread = require("multi"):init()
local function atomic(channel)
return channel:pop()
end
require("love.timer")
local clock = os.clock
local pad = require("multi.integration.loveManager.scratchpad")
local status = require("multi.integration.loveManager.status")
local funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table")
local queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue")
local queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn")
local lastProc = clock()
local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll")
local registry = {}
setmetatable(_G,{__index = funcs})
multi:newThread("startUp",function()
while true do
thread.yield()
local all = queueAll:peek()
if all and not registry[all[1]] then
lastProc = os.clock()
THREAD.loadDump(queueAll:pop()[2])()
end
end
end)
multi:newThread("runner",function()
thread.sleep(.1)
while true do
thread.yield()
local all = queueAll:peek()
if all and not registry[all[1]] then
lastProc = os.clock()
THREAD.loadDump(queueAll:pop()[2])()
end
local dat = queue:performAtomic(atomic)
if dat then
lastProc = os.clock()
local name = table.remove(dat,1)
local id = table.remove(dat,1)
local tab = {funcs[name](unpack(dat))}
table.insert(tab,1,id)
queueReturn:push(tab)
end
end
end):OnError(function(...)
error(...)
end)
multi:newThread("Idler",function()
while true do
thread.yield()
if clock()-lastProc> 2 then
THREAD.sleep(.05)
else
THREAD.sleep(.001)
end
end
end)
multi:mainloop()
end,jqc)
end
jqc = jqc + 1
return c
end

View File

@ -0,0 +1,33 @@
if ISTHREAD then
error("You cannot require the loveManager from within a thread!")
end
local multi, thread = require("multi.compat.love2d"):init()
local THREAD = {}
__THREADID__ = 0
__THREADNAME__ = "MainThread"
multi.integration={}
multi.integration.love2d={}
multi.integration.love2d.defaultScratchpadSize = 1024
multi.integration.love2d.GlobalScratchpad = love.data.newByteData(string.rep("\0",16*multi.integration.love2d.defaultScratchpadSize))
local THREAD = require("multi.integration.loveManager.threads")
local scratchpad = require("multi.integration.loveManager.scratchpad")
local STATUS = require("multi.integration.loveManager.status")
local GLOBAL = THREAD.getGlobal()
local THREAD_ID = 1 -- The Main thread has ID of 0
local OBJECT_ID = 0
function multi:newSystemThread(name,func,...)
local c = {}
c.scratchpad = love.data.newByteData(string.rep("\0",multi.integration.love2d.defaultScratchpadSize))
c.name = name
c.ID=THREAD_ID
c.thread=love.thread.newThread("multi/integration/loveManager/threadREF.lua")
c.thread:start(THREAD.dump(func),c.ID,c.name,c.scratchpad,multi.integration.love2d.GlobalScratchpad,...)
GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread}
GLOBAL["__THREAD_COUNT"] = THREAD_ID
THREAD_ID=THREAD_ID+1
end
multi.integration.GLOBAL = GLOBAL
multi.integration.THREAD = THREAD
return {init=function()
return GLOBAL,THREAD
end}

View File

@ -0,0 +1,41 @@
local ffi = require("ffi")
local scratchpad = {}
local mt = {
__index = function(t, k)
if type(k)=="string" then
local a, b = k:match("(%d+):(%d+)")
return t:read(tonumber(a),tonumber(b))
elseif type(k)=="number" then
return t:read(k,1)
end
end,
__newindex = function(t, k, v)
t:write(v,k)
end
}
function scratchpad:new(data, size, rep)
local c = {}
local pad
if type(data)=="string" then
pad = love.data.newByteData(data or string.rep(rep or "\0",size or 16))
elseif data:type()=="ByteData" then
pad = data
end
local ptr = ffi.cast("unsigned char*",pad:getPointer())
local size = pad:getSize()
function c:write(data, loc, len)
if (loc or 0)+(len or #data)>size then
error("Attpemting to write data outside the bounds of data byte array!")
end
ffi.copy(ptr+(loc or 0), data, len or #data)
end
function c:read(loc, len)
if (((loc or 0)+(len or size)) > size) or ((loc or 0)<0) then
error("Attempt to read outside the bounds of the scratchpad!")
end
return ffi.string(ptr+(loc or 0), len or size)
end
setmetatable(c,mt)
return c
end
return scratchpad

View File

@ -0,0 +1,13 @@
--[[
global pads allow us to directly write data to threads. Each thread has a unique ID which means we can allocate space in memory for each thread to relay stats
Below are codes, If there is more data that needs to be sent we can use byte 0 for that and byte 1,2 and 3 to define a channel
]]
local char = string.char
local cmds = {
OK = char(0x00), -- All is good thread is running can recieve and send data
ERR = char(0x01), -- This tells the system that an error has occured
STOP = char(0x02), -- Thread has finished
BUSY = char(0x03), -- Thread is busy and isn't responding to messages right now
POST = char(0x04), -- Important message for other threads to see, ChannelData with message MSG_TID
}
return cmds

View File

@ -0,0 +1,13 @@
ISTHREAD = true
THREAD = require("multi.integration.loveManager.threads") -- order is important!
scratchpad = require("multi.integration.loveManager.scratchpad")
STATUS = require("multi.integration.loveManager.status")
__IMPORTS = {...}
__FUNC__=table.remove(__IMPORTS,1)
__THREADID__=table.remove(__IMPORTS,1)
__THREADNAME__=table.remove(__IMPORTS,1)
pad=table.remove(__IMPORTS,1)
globalhpad=table.remove(__IMPORTS,1)
GLOBAL = THREAD.getGlobal()
multi, thread = require("multi").init()
THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))

View File

@ -0,0 +1,208 @@
--[[
Shared methods for both the main thread and
]]
require("love.timer")
require("love.system")
require("love.data")
local socket = require("socket")
local multi, thread = require("multi").init()
local threads = {}
function threads.loadDump(d)
return loadstring(d:getString())
end
function threads.dump(func)
return love.data.newByteData(string.dump(func))
end
local fRef = {"func",nil}
local function manage(channel, value)
channel:clear()
if type(value) == "function" then
fRef[2] = THREAD.dump(value)
channel:push(fRef)
return
else
channel:push(value)
end
end
local function RandomVariable(length)
local res = {}
math.randomseed(socket.gettime()*10000)
for i = 1, length do
res[#res+1] = string.char(math.random(97, 122))
end
return table.concat(res)
end
local GNAME = "__GLOBAL_"
local proxy = {}
function threads.set(name,val)
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
proxy[name]:performAtomic(manage, val)
end
function threads.get(name)
if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end
local dat = proxy[name]:peek()
if type(dat)=="table" and dat[1]=="func" then
return THREAD.loadDump(dat[2])
else
return dat
end
end
function threads.waitFor(name)
if thread.isThread() then
return thread.hold(function()
return threads.get(name)
end)
end
while threads.get(name)==nil do
love.timer.sleep(.001)
end
local dat = threads.get(name)
if type(dat) == "table" and dat.init then
dat.init = threads.loadDump(dat.init)
end
return dat
end
function threads.package(name,val)
local init = val.init
val.init=threads.dump(val.init)
GLOBAL[name]=val
val.init=init
end
function threads.testFor(name,val,sym)
-- Not yet implemented
end
function threads.getCores()
return love.system.getProcessorCount()
end
function threads.kill()
end
function threads.getThreads()
local t = {}
for i=1,GLOBAL["__THREAD_COUNT"] do
t[#t+1]=GLOBAL["__THREAD_"..i]
end
return t
end
function threads.getThread(n)
return GLOBAL["__THREAD_"..n]
end
function threads.getName()
return __THREADNAME__
end
function threads.getID()
return __THREADID__
end
function threads.sleep(n)
love.timer.sleep(n)
end
function threads.getGlobal()
return setmetatable({},
{
__index = function(t, k)
return THREAD.get(k)
end,
__newindex = function(t, k, v)
THREAD.set(k,v)
end
}
)
end
function threads.createTable(n)
local _proxy = {}
local function set(name,val)
if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end
_proxy[name]:performAtomic(manage, val)
end
local function get(name)
if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end
local dat = _proxy[name]:peek()
if type(dat)=="table" and dat[1]=="func" then
return THREAD.loadDump(dat[2])
else
return dat
end
end
return setmetatable({},
{
__index = function(t, k)
return get(k)
end,
__newindex = function(t, k, v)
set(k,v)
end
}
)
end
function threads.getConsole()
local c = {}
c.queue = love.thread.getChannel("__CONSOLE__")
function c.print(...)
c.queue:push{...}
end
function c.error(err)
c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__}
error(err)
end
return c
end
if not ISTHREAD then
print("mainthread")
local clock = os.clock
local lastproc = clock()
local queue = love.thread.getChannel("__CONSOLE__")
multi:newThread("consoleManager",function()
while true do
thread.yield()
dat = queue:pop()
if dat then
lastproc = clock()
print(unpack(dat))
end
if clock()-lastproc>2 then
thread.sleep(.1) -- Printing is for humans, sleep can be big to lower processing
end
end
end)
end
function threads.createStaticTable(n)
local __proxy = {}
local function set(name,val)
if __proxy[name] then return end
local chan = love.thread.getChannel(n..name)
if chan:getCount()>0 then return end
chan:performAtomic(manage, val)
__proxy[name] = val
end
local function get(name)
if __proxy[name] then return __proxy[name] end
local dat = love.thread.getChannel(n..name):peek()
if type(dat)=="table" and dat[1]=="func" then
__proxy[name] = THREAD.loadDump(dat[2])
return __proxy[name]
else
__proxy[name] = dat
return __proxy[name]
end
end
return setmetatable({},
{
__index = function(t, k)
return get(k)
end,
__newindex = function(t, k, v)
set(k,v)
end
}
)
end
function threads.hold(n)
local dat
while not(dat) do
dat = n()
end
end
return threads

View File

@ -25,80 +25,6 @@ local multi, thread = require("multi").init()
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 both 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
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 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 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
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 easier, create the linda on the main thread
function c:push(v) -- push to the queue
self.linda:send("Q", v)
@ -113,7 +39,6 @@ function multi:newSystemThreadedQueue(name) -- in love2d this will spawn a chann
return self
end
multi.integration.GLOBAL[name] = c -- send the object to the thread through the global interface
end
return c
end