v13.0.0 #11
@ -316,6 +316,7 @@ All of these functions are found on actors
|
||||
`self = multiObj:OnTimedOut(func)` -- If ResolveTimer was not called in time this event will be triggered. The function connected to it get a refrence of the original object that the timer was created on as the first argument.
|
||||
`self = multiObj:OnTimerResolved(func)` -- This event is triggered when the timer gets resolved. Same argument as above is passed, but the variable arguments that are accepted in resolvetimer are also passed as well.
|
||||
`self = multiObj:Reset(n)` -- In the cases where it isn't obvious what it does, it acts as Resume()
|
||||
`self = multiObj:SetName(STRING name)`
|
||||
|
||||
Actor: Events
|
||||
------
|
||||
@ -822,6 +823,7 @@ ST - THREAD namespace
|
||||
`THREAD.getName()` -- Returns the name of the working thread
|
||||
`THREAD.sleep(NUMBER n)` -- Sleeps for an amount of time stopping the current thread
|
||||
`THREAD.hold(FUNCTION func)` -- Holds the current thread until a condition is met
|
||||
`THREAD.getID()` -- returns a unique ID for the current thread. This varaiable is visible to the main thread as well by accessing it through the returned thread object. OBJ.Id
|
||||
|
||||
ST - GLOBAL namespace
|
||||
---------------------
|
||||
@ -835,6 +837,7 @@ ST - System Threads
|
||||
-------------------
|
||||
`systemThread = multi:newSystemThread(STRING thread_name,FUNCTION spawned_function,ARGUMENTS ...)` -- Spawns a thread with a certain name.
|
||||
`systemThread:kill()` -- kills a thread; can only be called in the main thread!
|
||||
`systemThread.OnError(FUNCTION(systemthread,errMsg,errorMsgWithThreadName))`
|
||||
|
||||
System Threads are the feature that allows a user to interact with systen threads. It differs from regular coroutine based thread in how it can interact with variables. When using system threads the GLOBAL table is the "only way"* to send data. Spawning a System thread is really simple once all the required libraries are in place. See example below:
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#Changes
|
||||
[TOC]
|
||||
Update 13.0.0 So you documented it, finally! If I had a dollar for each time I found a bug working on 13.0.0 I'd be quite wealthy by now. How much lag could one expect when I've been coding with my own library wrong this entire time?
|
||||
Update 13.0.0 So you documented it, finally! If I had a dollar for each time I found a bug working on 13.0.0 I'd be quite wealthy by now.
|
||||
-------------
|
||||
**Quick note** on the 13.0.0 update:
|
||||
This update I went all in finding bugs and improving proformance within the library. I added some new features and the new task manager, which I used as a way to debug the library was a great help, so much so thats it is now a permanent feature. It's been about half a year since my last update, but so much work needed to be done. I hope you can find a use in your code to use my library. I am extremely proud of my work; 7 years of development, I learned so much about lua and programming through the creation of this library. It was fun, but there will always be more to add and bugs crawling there way in. I can't wait to see where this library goes in the future!
|
||||
@ -10,6 +10,7 @@ Changed:
|
||||
- A few things, to make concepts in the library more clear.
|
||||
- The way functions returned paused status. Before it would return "PAUSED" now it returns nil, true if paused
|
||||
- Modified the connection object to allow for some more syntaxial suger!
|
||||
- System threads now trigger an OnError connection that is a member of the object itself. multi.OnError() is no longer triggered for a system thread that crashes!
|
||||
|
||||
Connection Example:
|
||||
```lua
|
||||
@ -65,6 +66,7 @@ Added:
|
||||
- multi:getTasksDetails(STRING format) -- Simple function, will get massive updates in the future, as of right now It will print out the current processes that are running; listing their type, uptime, and priority. More useful additions will be added in due time. Format can be either a string "s" or "t" see below for the table format
|
||||
- multi:endTask(TID) -- Use multi:getTasksDetails("t") to get the tid of a task
|
||||
- multi:enableLoadDetection() -- Reworked how load detection works. It gives better values now, but it still needs some work before I am happy with it
|
||||
- THREAD.getID() -- returns a unique ID for the current thread. This varaiable is visible to the main thread as well by accessing it through the returned thread object. OBJ.Id Do not confuse this with thread.* this refers to the system threading interface
|
||||
|
||||
```lua
|
||||
package.path="?/init.lua;?.lua;"..package.path
|
||||
@ -109,7 +111,6 @@ Table format for getTasksDetails(STRING format)
|
||||
**Going forward:**
|
||||
- Add something
|
||||
|
||||
|
||||
Update 12.2.2 Time for some more bug fixes!
|
||||
-------------
|
||||
Fixed: multi.Stop() not actually stopping due to the new pirority management scheme and preformance boost changes.
|
||||
|
||||
@ -28,6 +28,7 @@ multi.Version = "13.0.0"
|
||||
multi._VERSION = "13.0.0"
|
||||
multi.stage = "stable"
|
||||
multi.__index = multi
|
||||
multi.Name = "multi.Root"
|
||||
multi.Mainloop = {}
|
||||
multi.Garbage = {}
|
||||
multi.ender = {}
|
||||
@ -159,7 +160,7 @@ function multi:getLoad()
|
||||
return bench
|
||||
end)
|
||||
bench = bench^1.5
|
||||
val = math.ceil((1-(bench/(multi.maxSpd/1.5)))*100)
|
||||
val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100)
|
||||
else
|
||||
busy = true
|
||||
local bench
|
||||
@ -170,7 +171,7 @@ function multi:getLoad()
|
||||
multi:uManager()
|
||||
end
|
||||
bench = bench^1.5
|
||||
val = math.ceil((1-(bench/(multi.maxSpd/1.5)))*100)
|
||||
val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100)
|
||||
busy = false
|
||||
end
|
||||
if val<0 then val = 0 end
|
||||
@ -330,11 +331,11 @@ function multi.AlignTable(tab)
|
||||
return table.concat(str,"\n")
|
||||
end
|
||||
local priorityTable = {[0]="Round-Robin",[1]="Just-Right",[2]="Top-heavy",[3]="Timed-Based-Balancer"}
|
||||
local ProcessName = {[true]="SubProcess",[false]="MainProcess"}
|
||||
local ProcessName = {[true]="SubProcessor",[false]="MainProcessor"}
|
||||
function multi:getTasksDetails(t)
|
||||
if t == "string" or not t then
|
||||
str = {
|
||||
{"Type","Uptime","Priority","TID"}
|
||||
{"Type <Identifier","Uptime","Priority","TID"}
|
||||
}
|
||||
local count = 0
|
||||
for i,v in pairs(self.Mainloop) do
|
||||
@ -350,13 +351,19 @@ function multi:getTasksDetails(t)
|
||||
end
|
||||
local s = multi.AlignTable(str)
|
||||
dat = ""
|
||||
dat2 = ""
|
||||
if multi.SystemThreads then
|
||||
for i = 1,#multi.SystemThreads do
|
||||
dat2 = dat2.."<SystemThread: "..multi.SystemThreads[i].Name.." | "..os.clock()-multi.SystemThreads[i].creationTime..">\n"
|
||||
end
|
||||
end
|
||||
if multi.scheduler then
|
||||
for i=1,#multi.scheduler.Threads do
|
||||
dat = dat .. "<THREAD: "..multi.scheduler.Threads[i].Name.." | "..os.clock()-multi.scheduler.Threads[i].creationTime..">\n"
|
||||
end
|
||||
return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(multi:getLoad(),2).."%\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: "..#multi.scheduler.Threads.."\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s.."\n\n"..dat
|
||||
return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(multi:getLoad(),2).."%\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: "..#multi.scheduler.Threads.."\nSystemThreads Running: "..#(multi.SystemThreads or {}).."\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s.."\n\n"..dat..dat2
|
||||
else
|
||||
return "Load on "..({[true]="SubProcess<"..(self.Name or "Unnamed")..">",[false]="MainProcess"})[self.Type=="process"]..": "..multi.Round(multi:getLoad(),2).."%\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: 0\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s
|
||||
return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(multi:getLoad(),2).."%\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: 0\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s..dat2
|
||||
end
|
||||
elseif t == "t" or t == "table" then
|
||||
str = {
|
||||
@ -366,12 +373,18 @@ function multi:getTasksDetails(t)
|
||||
SystemLoad = multi.Round(multi:getLoad(),2)
|
||||
}
|
||||
str.threads = {}
|
||||
str.systemthreads = {}
|
||||
for i,v in pairs(self.Mainloop) do
|
||||
str[#str+1]={Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = i}
|
||||
end
|
||||
for i=1,#multi.scheduler.Threads do
|
||||
str.threads[multi.scheduler.Threads[i].Name]={Uptime = os.clock()-multi.scheduler.Threads[i].creationTime}
|
||||
end
|
||||
if multi.canSystemThread then
|
||||
for i=1,#multi.SystemThreads do
|
||||
str.systemthreads[multi.SystemThreads[i].Name]={Uptime = os.clock()-multi.SystemThreads[i].creationTime}
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
end
|
||||
@ -1576,7 +1589,7 @@ function multi.initThreads()
|
||||
event:OnEvent(function(evnt)
|
||||
evnt.link.sleep=0
|
||||
evnt:Destroy()
|
||||
end)
|
||||
end):setName("multi.thread.skip")
|
||||
elseif ret[1]=="_hold_" then
|
||||
self.Threads[i].timer:Reset()
|
||||
self.Threads[i].sleep=math.huge
|
||||
@ -1589,7 +1602,7 @@ function multi.initThreads()
|
||||
multi.nextStep(function()
|
||||
evnt:Destroy()
|
||||
end)
|
||||
end)
|
||||
end):setName("multi.thread.hold")
|
||||
elseif ret.Name then
|
||||
self.Globals[ret.Name]=ret.Value
|
||||
end
|
||||
|
||||
@ -32,6 +32,8 @@ end
|
||||
-- Step 1 get lanes
|
||||
lanes=require("lanes").configure()
|
||||
local multi = require("multi") -- get it all and have it on all lanes
|
||||
multi.SystemThreads = {}
|
||||
local thread = thread
|
||||
multi.isMainThread=true
|
||||
function multi:canSystemThread()
|
||||
return true
|
||||
@ -93,6 +95,9 @@ end
|
||||
function THREAD.getName()
|
||||
return THREAD_NAME
|
||||
end
|
||||
function THREAD.getID()
|
||||
return THREAD_ID
|
||||
end
|
||||
--[[ Step 4 We need to get sleeping working to handle timing... We want idle wait, not busy wait
|
||||
Idle wait keeps the CPU running better where busy wait wastes CPU cycles... Lanes does not have a sleep method
|
||||
however, a linda recieve will in fact be a idle wait! So we use that and wrap it in a nice package]]
|
||||
@ -109,17 +114,32 @@ function THREAD.hold(n)
|
||||
end
|
||||
local rand = math.random(1,10000000)
|
||||
-- Step 5 Basic Threads!
|
||||
-- local threads = {}
|
||||
local count = 0
|
||||
local started
|
||||
function multi:newSystemThread(name,func,...)
|
||||
multi.InitSystemThreadErrorHandler()
|
||||
rand = math.random(1,10000000)
|
||||
local c={}
|
||||
local __self=c
|
||||
c.name=name
|
||||
c.Name = name
|
||||
c.Id = count
|
||||
local THREAD_ID = count
|
||||
count = count + 1
|
||||
c.Type="sthread"
|
||||
c.creationTime = os.clock()
|
||||
local THREAD_NAME=name
|
||||
local function func2(...)
|
||||
local multi = require("multi")
|
||||
_G["THREAD_NAME"]=THREAD_NAME
|
||||
_G["THREAD_ID"]=THREAD_ID
|
||||
math.randomseed(rand)
|
||||
func(...)
|
||||
if _G.__Needs_Multi then
|
||||
multi:mainloop()
|
||||
end
|
||||
THREAD.kill()
|
||||
end
|
||||
c.thread=lanes.gen("*", func2)(...)
|
||||
function c:kill()
|
||||
@ -127,16 +147,32 @@ function multi:newSystemThread(name,func,...)
|
||||
self.thread:cancel()
|
||||
print("Thread: '"..self.name.."' has been stopped!")
|
||||
end
|
||||
c.status=multi:newUpdater(multi.Priority_IDLE)
|
||||
c.status.link=c
|
||||
c.status:OnUpdate(function(self)
|
||||
local v,err,t=self.link.thread:join(.001)
|
||||
table.insert(multi.SystemThreads,c)
|
||||
c.OnError = multi:newConnection()
|
||||
return c
|
||||
end
|
||||
function multi.InitSystemThreadErrorHandler()
|
||||
if started then return end
|
||||
multi:newThread("ThreadErrorHandler",function()
|
||||
local deadThreads = {}
|
||||
local threads = multi.SystemThreads
|
||||
while true do
|
||||
thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough.
|
||||
for i=#threads,1,-1 do
|
||||
local v,err,t=threads[i].thread:join(.001)
|
||||
if err then
|
||||
multi.OnError:Fire(self.link,err,"Error in systemThread: '"..self.link.name.."' <"..err..">")
|
||||
self:Destroy()
|
||||
if err:find("Thread was killed!") then
|
||||
table.remove(threads,i)
|
||||
else
|
||||
threads[i].OnError:Fire(threads[i],err,"Error in systemThread: '"..threads[i].name.."' <"..err..">")
|
||||
table.remove(threads,i)
|
||||
table.insert(deadThreads,threads[i].Id)
|
||||
GLOBAL["__DEAD_THREADS__"]=deadThreads
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
return c
|
||||
end
|
||||
print("Integrated Lanes!")
|
||||
multi.integration={} -- for module creators
|
||||
|
||||
@ -34,6 +34,7 @@ multi.integration.love2d.ThreadBase=[[
|
||||
tab={...}
|
||||
__THREADID__=table.remove(tab,1)
|
||||
__THREADNAME__=table.remove(tab,1)
|
||||
THREAD_ID=table.remove(tab,1)
|
||||
require("love.filesystem")
|
||||
require("love.system")
|
||||
require("love.timer")
|
||||
@ -217,6 +218,9 @@ isMainThread=true
|
||||
function THREAD.getName()
|
||||
return __THREADNAME__
|
||||
end
|
||||
function THREAD.getID()
|
||||
return THREAD_ID
|
||||
end
|
||||
function ToStr(val, name, skipnewlines, depth)
|
||||
skipnewlines = skipnewlines or false
|
||||
depth = depth or 0
|
||||
@ -295,12 +299,16 @@ local function randomString(n)
|
||||
end
|
||||
return str
|
||||
end
|
||||
local count = 0
|
||||
function multi:newSystemThread(name,func,...) -- the main method
|
||||
local c={}
|
||||
c.name=name
|
||||
c.Name = name
|
||||
c.ID=c.name.."<ID|"..randomString(8)..">"
|
||||
c.Id=count
|
||||
count = count + 1
|
||||
c.thread=love.thread.newThread(multi.integration.love2d.ThreadBase:gsub("INSERT_USER_CODE",dump(func)))
|
||||
c.thread:start(c.ID,c.name,...)
|
||||
c.thread:start(c.ID,c.name,,...)
|
||||
function c:kill()
|
||||
multi.integration.GLOBAL["__DIEPLZ"..self.ID.."__"]="__DIEPLZ"..self.ID.."__"
|
||||
end
|
||||
|
||||
@ -123,6 +123,7 @@ function multi:newSystemThreadedConnection(name,protect)
|
||||
local qsm = multi:newSystemThreadedQueue(name.."THREADED_CALLSYNCM"):init()
|
||||
local qs = multi:newSystemThreadedQueue(name.."THREADED_CALLSYNC"):init()
|
||||
function c:init()
|
||||
_G.__Needs_Multi = true
|
||||
local multi = require("multi")
|
||||
if multi:getPlatform()=="love2d" then
|
||||
GLOBAL=_G.GLOBAL
|
||||
@ -241,6 +242,7 @@ function multi:newSystemThreadedConsole(name)
|
||||
local sThread=multi.integration.THREAD
|
||||
local GLOBAL=multi.integration.GLOBAL
|
||||
function c:init()
|
||||
_G.__Needs_Multi = true
|
||||
local multi = require("multi")
|
||||
if multi:getPlatform()=="love2d" then
|
||||
GLOBAL=_G.GLOBAL
|
||||
@ -288,6 +290,7 @@ function multi:newSystemThreadedTable(name)
|
||||
local sThread=multi.integration.THREAD
|
||||
local GLOBAL=multi.integration.GLOBAL
|
||||
function c:init() -- create an init function so we can mimic on both love2d and lanes
|
||||
_G.__Needs_Multi = true
|
||||
local multi = require("multi")
|
||||
if multi:getPlatform()=="love2d" then
|
||||
GLOBAL=_G.GLOBAL
|
||||
|
||||
17
test.lua
17
test.lua
@ -10,7 +10,7 @@ function sleep(n) -- seconds
|
||||
end
|
||||
master = multi:newMaster{
|
||||
name = "Main", -- the name of the master
|
||||
--noBroadCast = true, -- if using the node manager, set this to true to avoid double connections
|
||||
--~ --noBroadCast = true, -- if using the node manager, set this to true to avoid double connections
|
||||
managerDetails = {"192.168.1.4",12345}, -- the details to connect to the node manager (ip,port)
|
||||
}
|
||||
master.OnError(function(name,err)
|
||||
@ -28,9 +28,20 @@ end)
|
||||
master.OnNodeConnected(function(name)
|
||||
table.insert(connlist,name)
|
||||
end)
|
||||
multi.OnError(function(...)
|
||||
print(...)
|
||||
--~ multi:newThread("TaskView",function()
|
||||
--~ while true do
|
||||
--~ thread.sleep(1)
|
||||
--~ print(multi:getTasksDetails())
|
||||
--~ end
|
||||
--~ end)
|
||||
multi:newSystemThread("SystemThread",function()
|
||||
local multi = require("multi")
|
||||
print(THREAD.getName(),THREAD.getID())
|
||||
THREAD.sleep(8)
|
||||
end).OnError(function(a,b,c)
|
||||
print("ERROR:",b)
|
||||
end)
|
||||
--~ print(multi:getTasksDetails())
|
||||
multi:mainloop{
|
||||
protect = false
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user