Working on psuedo threading

This commit is contained in:
Ryan Ward 2020-05-08 11:41:52 -04:00
parent 61dcb9da01
commit 9d97eac146
4 changed files with 171 additions and 8 deletions

View File

@ -24,18 +24,48 @@ for i = 1,100 do
end)
end
test = true
local haha = true
multi:newThread("Standard Thread 1",function()
print(self.Name,haha)
while true do
thread.sleep(1)
print("Testing "..self.Name..":",test)
thread.sleep(.1)
prient("...")
end
end)
multi:newThread("Standard Thread 2",function()
print(self.Name)
while true do
thread.sleep(1)
print("Testing "..self.Name..":",test)
end
end)
multi:newISOThread("Isolated Thread",function()
while true do
thread.sleep(1)
print("Testing Isolated:",test)
--errhor("huh")
end
end).OnError(function(...)
print(...)
end)
multi:lightloop()
```
Added:
---
- multi:newISOThread(name,func)
- Creates an isolated thread that prevents both locals and globals from being accessed.
- Added new integration: pesudoManager, functions just like lanesManager and loveManager, but it's actually single threaded
- This was implemented because, you may want to build your code around being multi threaded, but some systems/implemetations of lua may not permit this. Since we now have a "single threaded" implementation of multi threading. We can actually create scalable code where things automatcally are threaded if built correctly. I am planning on adding more threadedOjbects.
- In addition to adding pesudo Threading `multi.integration.threading` can now be used to autodetect which enviroment you are on and use the threading features.
```
GLOBAL,THREAD = require("multi.integration.threading"):init()
```
If you are using love2d it will use that, if you have lanes avaialble then it will use lanes. Otherwise it will use pesudo threading. This allows module creators to implement scalable features without having to worry about which enviroment they are in. And it's my job to ensure everything works properly within reason.
If you are using love2d it will use that, if you have lanes avaialble then it will use lanes. Otherwise it will use pesudo threading. This allows module creators to implement scalable features without having to worry about which enviroment they are in.
Fixed:
---

View File

@ -1072,13 +1072,21 @@ function thread:newFunction(func,holdme)
return temp
end
end
-- A cross version way to set enviroments, not the same as fenv though
function multi.setEnv(func,env)
local f = string.dump(func)
local chunk = load(f,"env","bt",env)
return chunk
end
function multi:newThread(name,func,...)
multi.OnLoad:Fire()
local func = func or name
if type(name) == "function" then
name = "Thread#"..threadCount
end
local env = {}
local c={}
local env = {self=c}
setmetatable(env,{
__index = Gref,
__newindex = function(t,k,v)
@ -1090,7 +1098,117 @@ function multi:newThread(name,func,...)
end
})
setfenv(func,env)
c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
c.startArgs = {...}
c.ref={}
c.Name=name
c.thread=coroutine.create(func)
c.sleep=1
c.Type="thread"
c.TID = threadid
c.firstRunDone=false
c.timer=multi:newTimer()
c._isPaused = false
c.returns = {}
c.OnError = multi:newConnection(true,nil,true)
c.OnDeath = multi:newConnection(true,nil,true)
function c:isPaused()
return self._isPaused
end
local resumed = false
function c:Pause()
if not self._isPaused then
thread.request(self,"exec",function()
thread.hold(function()
return resumed
end)
resumed = false
self._isPaused = false
end)
self._isPaused = true
end
return self
end
function c:Resume()
resumed = true
return self
end
function c:Kill()
thread.request(self,"kill")
return self
end
c.Destroy = c.Kill
function c.ref:send(name,val)
ret=coroutine.yield({Name=name,Value=val})
end
function c.ref:get(name)
return self.Globals[name]
end
function c.ref:kill()
dRef[1] = "_kill_"
dRef[2] = "I Was killed by You!"
err = coroutine.yield(dRef)
if err then
error("Failed to kill a thread! Exiting...")
end
end
function c.ref:sleep(n)
if type(n)=="function" then
ret=thread.hold(n)
elseif type(n)=="number" then
ret=thread.sleep(tonumber(n) or 0)
else
error("Invalid Type for sleep!")
end
end
function c.ref:syncGlobals(v)
self.Globals=v
end
table.insert(threads,c)
if initT==false then
multi.initThreads()
end
c.creationTime = os.clock()
threadid = threadid + 1
self:create(c)
return c
end
function multi:newISOThread(name,func,...)
multi.OnLoad:Fire()
local func = func or name
if type(name) == "function" then
name = "Thread#"..threadCount
end
local env = {
thread = thread,
multi = multi,
coroutine = coroutine,
debug = debug,
io = io,
math = math,
os = os,
package = package,
string = string,
table = table,
utf8 = utf8
}
for i,v in pairs(_G) do
if tostring(v):match("builtin") then
env[i]=v
end
end
setmetatable(env,{
__newindex = function(t,k,v)
if type(v)=="function" then
rawset(t,k,thread:newFunction(v))
else
Gref[k]=v
end
end
})
local func = multi.setEnv(func,env)
local c={}
env.self = c
c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
c.startArgs = {...}
c.ref={}
@ -1255,9 +1373,11 @@ function multi.initThreads(justThreads)
multi.scheduler:OnLoop(function(self)
for i=#threads,1,-1 do
if threads[i].isError then
threads[i].OnError:Fire(threads[i],unpack(threads[i].TempRets))
multi.setType(threads[i],multi.DestroyedObj)
table.remove(threads,i)
if coroutine.status(threads[i].thread)=="dead" then
threads[i].OnError:Fire(threads[i],unpack(threads[i].TempRets))
multi.setType(threads[i],multi.DestroyedObj)
table.remove(threads,i)
end
end
if threads[i] and not threads[i].__started then
if coroutine.running() ~= threads[i].thread then

View File

@ -43,7 +43,9 @@ function multi:getPlatform()
end
THREAD.newFunction=thread.newFunction
multi.newSystemThread = multi.newThread
multi.newSystemThread = multi.newISOThread
-- System threads as implemented here cannot share memory, but use a message passing system.
-- An isolated thread allows us to mimic that behavior so if access data from the "main" thread happens things will not work. This behavior is in line with how the system threading works
print("Integrated Pesudo Threading!")
multi.integration = {} -- for module creators

View File

@ -1,7 +1,18 @@
package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path
multi,thread = require("multi"):init()
GLOBAL,THREAD = require("multi.integration.pesudoManager"):init()
test = true
local haha = true
jq = multi:newSystemThreadedJobQueue(100) -- Job queue with 4 worker threads
func = jq:newFunction("test",function(a,b)
THREAD.sleep(2)
return a+b
end)
for i = 1,100 do
func(i,i*3).connect(function(data)
print(data)
end)
end
multi:mainloop({print=true})
multi:mainloop()