From 61dcb9da01b958d457d1e9d95836f8c72f357bd7 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Sun, 29 Mar 2020 11:50:15 -0400 Subject: [PATCH] Working on 15.0.0 --- README.md | 4 +- changes.md | 37 +++++ multi/init.lua | 5 +- multi/integration/lanesManager/extensions.lua | 2 +- multi/integration/lanesManager/init.lua | 4 +- multi/integration/lanesManager/threads.lua | 2 +- multi/integration/loveManager/extensions.lua | 2 +- multi/integration/loveManager/init.lua | 1 + .../integration/pesudoManager/extensions.lua | 126 ++++++++++++++++++ multi/integration/pesudoManager/init.lua | 57 ++++++++ multi/integration/pesudoManager/threads.lua | 96 +++++++++++++ multi/integration/threading.lua | 13 ++ test.lua | 43 +----- 13 files changed, 344 insertions(+), 48 deletions(-) create mode 100644 multi/integration/pesudoManager/extensions.lua create mode 100644 multi/integration/pesudoManager/init.lua create mode 100644 multi/integration/pesudoManager/threads.lua create mode 100644 multi/integration/threading.lua diff --git a/README.md b/README.md index 7c80ef8..c955b01 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# Multi Version: 14.2.0 Documentation Complete, Bloat removed! +# Multi Version: 15.0.0 Fake it, until you make it +**Key Changes** +- Emulating system threading on a single thread Found an issue? Please [submit it](https://github.com/rayaman/multi/issues) and I'll look into it! diff --git a/changes.md b/changes.md index 3a60bcc..b359dfd 100644 --- a/changes.md +++ b/changes.md @@ -4,6 +4,43 @@ Table of contents --- [Update 14.2.0 - Bloatware Removed](#update-1420---bloatware-removed)
[Update 14.1.0 - A whole new world of possibilities](#update-1410---a-whole-new-world-of-possibilities)
[Update 14.0.0 - Consistency, Additions and Stability](#update-1400---consistency-additions-and-stability)
[Update 13.1.0 - Bug fixes and features added](#update-1310---bug-fixes-and-features-added)
[Update 13.0.0 - Added some documentation, and some new features too check it out!](#update-1300---added-some-documentation-and-some-new-features-too-check-it-out)
[Update 12.2.2 - Time for some more bug fixes!](#update-1222---time-for-some-more-bug-fixes)
[Update 12.2.1 - Time for some bug fixes!](#update-1221---time-for-some-bug-fixes)
[Update 12.2.0 - The chains of binding](#update-1220---the-chains-of-binding)
[Update 12.1.0 - Threads just can't hold on anymore](#update-1210---threads-just-cant-hold-on-anymore)
[Update: 12.0.0 - Big update (Lots of additions some changes)](#update-1200---big-update-lots-of-additions-some-changes)
[Update: 1.11.1 - Small Clarification on Love](#update-1111---small-clarification-on-love)
[Update: 1.11.0](#update-1110)
[Update: 1.10.0](#update-1100)
[Update: 1.9.2](#update-192)
[Update: 1.9.1 - Threads can now argue](#update-191---threads-can-now-argue)
[Update: 1.9.0](#update-190)
[Update: 1.8.7](#update-187)
[Update: 1.8.6](#update-186)
[Update: 1.8.5](#update-185)
[Update: 1.8.4](#update-184)
[Update: 1.8.3 - Mainloop recieves some needed overhauling](#update-183---mainloop-recieves-some-needed-overhauling)
[Update: 1.8.2](#update-182)
[Update: 1.8.1](#update-181)
[Update: 1.7.6](#update-176)
[Update: 1.7.5](#update-175)
[Update: 1.7.4](#update-174)
[Update: 1.7.3](#update-173)
[Update: 1.7.2](#update-172)
[Update: 1.7.1 - Bug Fixes Only](#update-171---bug-fixes-only)
[Update: 1.7.0 - Threading the systems](#update-170---threading-the-systems)
[Update: 1.6.0](#update-160)
[Update: 1.5.0](#update-150)
[Update: 1.4.1 (4/10/2017) - First Public release of the library](#update-141-4102017---first-public-release-of-the-library)
[Update: 1.4.0 (3/20/2017)](#update-140-3202017)
[Update: 1.3.0 (1/29/2017)](#update-130-1292017)
[Update: 1.2.0 (12.31.2016)](#update-120-12312016)
[Update: 1.1.0](#update-110)
[Update: 1.0.0](#update-100)
[Update: 0.6.3](#update-063)
[Update: 0.6.2](#update-062)
[Update: 0.6.1-6](#update-061-6)
[Update: 0.5.1-6](#update-051-6)
[Update: 0.4.1](#update-041)
[Update: 0.3.0 - The update that started it all](#update-030---the-update-that-started-it-all)
[Update: EventManager 2.0.0](#update-eventmanager-200)
[Update: EventManager 1.2.0](#update-eventmanager-120)
[Update: EventManager 1.1.0](#update-eventmanager-110)
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different) +# Update 15.0.0 - The art of faking it +Full Update Showcase +--- +```lua +package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path +multi,thread = require("multi"):init() +GLOBAL,THREAD = require("multi.integration.threading"):init() -- Auto detects your enviroment and uses what's available + +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:lightloop() +``` + +Added: +--- +- 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. + +Fixed: +--- +- lanesManager THREAD:get(STRING: name) not returning the value + # Update 14.2.0 - Bloatware Removed Full Update Showcase --- diff --git a/multi/init.lua b/multi/init.lua index 896d209..4d0547c 100644 --- a/multi/init.lua +++ b/multi/init.lua @@ -30,7 +30,7 @@ if not _G["$multi"] then _G["$multi"] = {multi=multi,thread=thread} end -multi.Version = "14.2.0" +multi.Version = "15.0.0" multi.stage = "stable" multi.Name = "multi.root" multi.Mainloop = {} @@ -1430,7 +1430,8 @@ end function multi:threadloop() multi.initThreads(true) end -function multi:lightloop() +function multi:lightloop(settings) + multi.defaultSettings = settings or multi.defaultSettings if not isRunning then local Loop=self.Mainloop while true do diff --git a/multi/integration/lanesManager/extensions.lua b/multi/integration/lanesManager/extensions.lua index 2fafd5b..ddb6525 100644 --- a/multi/integration/lanesManager/extensions.lua +++ b/multi/integration/lanesManager/extensions.lua @@ -100,7 +100,7 @@ function multi:newSystemThreadedJobQueue(n) link = c.OnJobCompleted(function(jid,...) if id==jid then rets = {...} - link:Remove() + link:Destroy() end end) return thread.hold(function() diff --git a/multi/integration/lanesManager/init.lua b/multi/integration/lanesManager/init.lua index 995cf0e..db771d4 100644 --- a/multi/integration/lanesManager/init.lua +++ b/multi/integration/lanesManager/init.lua @@ -23,7 +23,7 @@ SOFTWARE. ]] package.path = "?/init.lua;?.lua;" .. package.path multi, thread = require("multi").init() -- get it all and have it on all lanes -if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel +if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassle return { init = function() return multi.integration.GLOBAL, multi.integration.THREAD @@ -145,7 +145,7 @@ function multi.InitSystemThreadErrorHandler() end ) end -multi.print("Integrated Lanes!") +print("Integrated Lanes!") multi.integration = {} -- for module creators multi.integration.GLOBAL = GLOBAL multi.integration.THREAD = THREAD diff --git a/multi/integration/lanesManager/threads.lua b/multi/integration/lanesManager/threads.lua index 33abc88..d038f1e 100644 --- a/multi/integration/lanesManager/threads.lua +++ b/multi/integration/lanesManager/threads.lua @@ -41,7 +41,7 @@ local function INIT(__GlobalLinda,__SleepingLinda) __GlobalLinda:set(name, val) end function THREAD.get(name) - __GlobalLinda:get(name) + return __GlobalLinda:get(name) end function THREAD.waitFor(name) local function wait() diff --git a/multi/integration/loveManager/extensions.lua b/multi/integration/loveManager/extensions.lua index add2234..cbeecf3 100644 --- a/multi/integration/loveManager/extensions.lua +++ b/multi/integration/loveManager/extensions.lua @@ -116,7 +116,7 @@ function multi:newSystemThreadedJobQueue(n) link = c.OnJobCompleted(function(jid,...) if id==jid then rets = {...} - link:Remove() + link:Destroy() end end) return thread.hold(function() diff --git a/multi/integration/loveManager/init.lua b/multi/integration/loveManager/init.lua index cf2054d..b88ffd3 100644 --- a/multi/integration/loveManager/init.lua +++ b/multi/integration/loveManager/init.lua @@ -81,6 +81,7 @@ end multi.integration.GLOBAL = GLOBAL multi.integration.THREAD = THREAD require("multi.integration.loveManager.extensions") +print("Integrated Love Threading!") return {init=function() return GLOBAL,THREAD end} \ No newline at end of file diff --git a/multi/integration/pesudoManager/extensions.lua b/multi/integration/pesudoManager/extensions.lua new file mode 100644 index 0000000..92c5889 --- /dev/null +++ b/multi/integration/pesudoManager/extensions.lua @@ -0,0 +1,126 @@ +--[[ +MIT License + +Copyright (c) 2020 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, sub-license, 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. +]] +local multi, thread = require("multi"):init() +local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD +function multi:newSystemThreadedQueue(name) + local c = {} + function c:push(v) + table.insert(self,v) + end + function c:pop() + return table.remove(self,1) + end + function c:peek() + return self[1] + end + function c:init() + return self + end + GLOBAL[name or "_"] = c + return c +end +function multi:newSystemThreadedTable(name) + local c = {} + function c:init() + return self + end + GLOBAL[name or "_"] = c + return c +end +local setfenv = setfenv +if not setfenv then + if not debug then + multi.print("Unable to implement setfenv in lua 5.2+ the debug module is not available!") + else + setfenv = function(f, env) + return load(string.dump(f), nil, nil, env) + end + end +end +function multi:newSystemThreadedJobQueue(n) + local c = {} + c.cores = n or THREAD.getCores()*2 + c.OnJobCompleted = multi:newConnection() + local jobs = {} + local ID=1 + local jid = 1 + local env = {} + setmetatable(env,{ + __index = _G + }) + local funcs = {} + function c:doToAll(func) + setfenv(func,env)() + return self + end + function c:registerFunction(name,func) + funcs[name] = setfenv(func,env) + return self + end + function c:pushJob(name,...) + table.insert(jobs,{name,jid,{...}}) + jid = jid + 1 + return jid-1 + end + local nFunc = 0 + function c:newFunction(name,func,holup) -- This registers with the queue + if type(name)=="function" then + holup = func + func = name + name = "JQ_Function_"..nFunc + end + nFunc = nFunc + 1 + c:registerFunction(name,func) + return thread:newFunction(function(...) + local id = c:pushJob(name,...) + local link + local rets + link = c.OnJobCompleted(function(jid,...) + if id==jid then + rets = {...} + link:Destroy() + end + end) + return thread.hold(function() + if rets then + return unpack(rets) or multi.NIL + end + end) + end,holup),name + end + for i=1,c.cores do + multi:newThread("PesudoThreadedJobQueue_"..i,function() + while true do + thread.yield() + if #jobs>0 then + local j = table.remove(jobs,1) + c.OnJobCompleted:Fire(j[2],funcs[j[1]](unpack(j[3]))) + else + thread.sleep(.05) + end + end + end) + end + return c +end \ No newline at end of file diff --git a/multi/integration/pesudoManager/init.lua b/multi/integration/pesudoManager/init.lua new file mode 100644 index 0000000..eb9b66f --- /dev/null +++ b/multi/integration/pesudoManager/init.lua @@ -0,0 +1,57 @@ +--[[ +MIT License + +Copyright (c) 2020 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, sub-license, 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. +]] +package.path = "?/init.lua;?.lua;" .. package.path +local multi, thread = require("multi").init() + +if multi.integration then + return { + init = function() + return multi.integration.GLOBAL, multi.integration.THREAD + end + } +end + +local GLOBAL, THREAD = require("multi.integration.pesudoManager.threads"):init() + +function multi:canSystemThread() -- We are emulating system threading + return true +end + +function multi:getPlatform() + return "pesudo" +end + +THREAD.newFunction=thread.newFunction +multi.newSystemThread = multi.newThread + +print("Integrated Pesudo Threading!") +multi.integration = {} -- for module creators +multi.integration.GLOBAL = GLOBAL +multi.integration.THREAD = THREAD +require("multi.integration.pesudoManager.extensions") +return { + init = function() + return GLOBAL, THREAD + end +} diff --git a/multi/integration/pesudoManager/threads.lua b/multi/integration/pesudoManager/threads.lua new file mode 100644 index 0000000..0c4f802 --- /dev/null +++ b/multi/integration/pesudoManager/threads.lua @@ -0,0 +1,96 @@ +--[[ +MIT License + +Copyright (c) 2020 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, sub-license, 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. +]] +local function getOS() + if package.config:sub(1, 1) == "\\" then + return "windows" + else + return "unix" + end +end +local function INIT() + local THREAD = {} + local GLOBAL = {} + THREAD.Priority_Core = 3 + THREAD.Priority_High = 2 + THREAD.Priority_Above_Normal = 1 + THREAD.Priority_Normal = 0 + THREAD.Priority_Below_Normal = -1 + THREAD.Priority_Low = -2 + THREAD.Priority_Idle = -3 + function THREAD.set(name, val) + GLOBAL[name] = val + end + function THREAD.get(name) + return GLOBAL[name] + end + function THREAD.waitFor(name) + return thread.hold(function() return GLOBAL[name] end) + end + if getOS() == "windows" then + THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) + end + function THREAD.getCores() + return THREAD.__CORES + end + function THREAD.getConsole() + local c = {} + function c.print(...) + print(...) + end + function c.error(err) + error("ERROR in <"..__THREADNAME__..">: "..err) + end + return c + end + function THREAD.getThreads() + return {}--GLOBAL.__THREADS__ + end + 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.kill() + error("Thread was killed!") + end + function THREAD.getName() + return THREAD_NAME + end + function THREAD.getID() + return THREAD_ID + end + _G.THREAD_ID = 0 + function THREAD.sleep(n) + thread.sleep(n) + end + function THREAD.hold(n) + return thread.hold(n) + end + return GLOBAL, THREAD +end +return {init = function() + return INIT() +end} \ No newline at end of file diff --git a/multi/integration/threading.lua b/multi/integration/threading.lua new file mode 100644 index 0000000..b75dbc6 --- /dev/null +++ b/multi/integration/threading.lua @@ -0,0 +1,13 @@ +-- We need to detect what enviroment we are running our code in. +return { + init = function() + if love then + return require("multi.integration.loveManager"):init() + else + if pcall(require,"lanes") then + return require("multi.integration.lanesManager"):init() + end + return require("multi.integration.pesudoManager"):init() + end + end +} \ No newline at end of file diff --git a/test.lua b/test.lua index e8b20d5..1f840a4 100644 --- a/test.lua +++ b/test.lua @@ -1,44 +1,7 @@ package.path="?.lua;?/init.lua;?.lua;?/?/init.lua;"..package.path -local multi,thread = require("multi"):init() +multi,thread = require("multi"):init() +GLOBAL,THREAD = require("multi.integration.pesudoManager"):init() --- Testing destroying and fixed connections -c = multi:newConnection() -c1 = c(function() - print("called 1") -end) -c2 = c(function() - print("called 2") -end) -c3 = c(function() - print("called 3") -end) -print(c1,c2.Type,c3) -c:Fire() -c2:Destroy() -print(c1,c2.Type,c3) -c:Fire() -c1:Destroy() -print(c1,c2.Type,c3) -c:Fire() --- Destroying alarms and threads -local test = multi:newThread(function() - while true do - thread.sleep(1) - print("Hello!") - end -end) - -test.OnDeath(function() - os.exit() -- This is the last thing called. -end) - -local alarm = multi:newAlarm(4):OnRing(function(a) - print(a.Type) - a:Destroy() - print(a.Type) - test:Destroy() -end) - -multi:lightloop() \ No newline at end of file +multi:mainloop({print=true}) \ No newline at end of file