diff --git a/changes.md b/changes.md index a32b0d9..09be44f 100644 --- a/changes.md +++ b/changes.md @@ -13,21 +13,42 @@ Full Update Showcase Added: --- -- multi:getThreads() - - Returns a list of all threads on a process -- multi:newProcessor(name,nothread).run() - - new function run to the processor object to +- `multi:lock()` + - Locks a multi object which prevents, Destroy(), Pause(), and Resume() being processed. -- multi:newProcessor(name,nothread):newFunction(func,holdme) +- `multi:unlock()` + - Undoes the lock + +- `multi:getProcessors()` + - Returns a list of all processors + +- `multi:getName()` + - Returns the name of a processor + +- `multi:getFullName()` + - Returns the fullname/entire process tree of a process + +- Processors can be attached to processors + +- `multi:getTasks()` + - Returns a list of all non thread based objects (loops, alarms, steps, etc) + +- `multi:getThreads()` + - Returns a list of all threads on a process + +- `multi:newProcessor(name,nothread).run()` + - New function run to the processor object to + +- `multi:newProcessor(name,nothread):newFunction(func,holdme)` - Acts like thread:newFunction(), but binds the execution of that threaded function to the processor -- multi:newTLoop() member functions +- `multi:newTLoop()` member functions - `TLoop:Set(set)` - Sets the time to wait for the TLoop -- multi:newStep() member functions +- `multi:newStep()` member functions - `Step:Count(count)` - Sets the amount a step should count by -- multi:newTStep() member functions +- `multi:newTStep()` member functions - `TStep:Set(set)` - Sets the time to wait for the TStep @@ -77,6 +98,7 @@ Changed: Status: Done 1 2 3 nil nil nil nil nil nil nil nil nil nil nil nil Function Done! ``` + - Modified how threads are handled internally. This changes makes it so threads "regardless of amount" should not impact performance. What you do in the threads might. This change was made by internally only processing one thread per step per processor. If you have 10 processors that are all active expect one step to process 10 threads. However if one processor has 10 threads each step will only process one thread. Simply put each addition of a thread shouldn't impact performance as it did before. - Moved `multi:newThread(...)` into the thread interface (`thread:newThread(...)`), code using `multi:newThread(...)` will still work. Also using `process:newThread(...)` binds the thread to the process, meaning if the process the thread is bound to is paused so is the thread. @@ -152,9 +174,13 @@ Removed: Fixed: --- -- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seems to be related to my filesystem + +- [Issue](https://github.com/rayaman/multi/issues/30) with Lanes crashing the lua state. Issue seemed to be related to my filesystem, since remounting the drive caused the issue to stop. (Windows) + - [Issue](https://github.com/rayaman/multi/issues/29) where System threaded functions not being up to date with threaded functions + - Issue where gettasksdetails() would try to process a destroyed object causing it to crash + - Issue with multi.hold() not pumping the mainloop and only the scheduler ToDo: diff --git a/multi/init.lua b/multi/init.lua index a59587b..60e026e 100644 --- a/multi/init.lua +++ b/multi/init.lua @@ -28,13 +28,14 @@ local isRunning = false local clock = os.clock local thread = {} local in_proc = false +local processes = {} if not _G["$multi"] then _G["$multi"] = {multi=multi,thread=thread} end multi.Version = "15.2.0" -multi.Name = "multi.root" +multi.Name = "root" multi.NIL = {Type="NIL"} local NIL = multi.NIL multi.Mainloop = {} @@ -85,6 +86,10 @@ local priorityTable = {[false]="Disabled",[true]="Enabled"} local ProcessName = {"SubProcessor","MainProcessor"} local globalThreads = {} +function multi:getProcessors() + return processes +end + function multi:getTasksDetails(t) if not(t) then str = { @@ -441,6 +446,14 @@ function multi:getType() return self.Type end +function multi:lock() + self.__locked = true +end + +function multi:unlock() + self.__locked = false +end + -- Advance Timer stuff function multi:SetTime(n) if not n then n=3 end @@ -473,6 +486,7 @@ end -- Timer stuff done multi.PausedObjects = {} function multi:Pause() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end if self.Type=='rootprocess' then multi.print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()") else @@ -490,6 +504,7 @@ function multi:Pause() end function multi:Resume() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end if self.Type=='process' or self.Type=='rootprocess' then self.Active=true local c=self:getChildren() @@ -507,6 +522,7 @@ function multi:Resume() end function multi:Destroy() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end if self.Type=='process' or self.Type=='rootprocess' then local c=self:getChildren() for i=1,#c do @@ -576,6 +592,7 @@ function multi:newBase(ins) c.Act=function() end c.Parent=self c.creationTime = os.clock() + c.__locked = false if ins then table.insert(self.Mainloop,ins,c) else @@ -690,6 +707,7 @@ function multi:newAlarm(set) end end function c:Resume() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end self.Parent.Resume(self) t = count + t return self @@ -702,6 +720,7 @@ function multi:newAlarm(set) end c.OnRing = self:newConnection() function c:Pause() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end count = clock() self.Parent.Pause(self) return self @@ -812,11 +831,13 @@ function multi:newTLoop(func,set) self.set = set end function c:Resume() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end self.Parent.Resume(self) self.timer:Resume() return self end function c:Pause() + if self.__locked then multi.print("Cannot perform action on a locked object!") return end self.timer:Pause() self.Parent.Pause(self) return self @@ -920,7 +941,16 @@ function multi.getCurrentTask() return __CurrentTask end +function multi:getName() + return self.Name +end + +function multi:getFullName() + return self.Name +end + local sandcount = 1 + function multi:newProcessor(name,nothread) local c = {} setmetatable(c,{__index = multi}) @@ -933,30 +963,45 @@ function multi:newProcessor(name,nothread) c.pump = false c.threads = {} c.startme = {} + c.parent = self local handler = c:createHandler(c.threads,c.startme) - c.process = multi:newLoop(function() + + c.process = self:newLoop(function() if Active then c:uManager() handler() end end) + c.process.isProcessThread = true c.process.PID = sandcount c.OnError = c.process.OnError + function c:getThreads() return self.threads end + + function c:getFullName() + return self.parent:getFullName() .. "." .. self.Name + end + + function c:getName() + return self.Name + end + function c:newThread(name,func,...) in_proc = c local t = thread.newThread(c,name,func,...) in_proc = false return t end + function c:newFunction(func,holdme) return thread:newFunctionBase(function(...) return c:newThread("TempThread",func,...) end,holdme)() end + function c.run() if not Active then return end c.pump = true @@ -965,21 +1010,27 @@ function multi:newProcessor(name,nothread) c.pump = false return c end + function c.isActive() return Active end + function c.Start() Active = true return c end + function c.Stop() Active = false return c end + function c:Destroy() Active = false c.process:Destroy() end + + table.insert(processes,c) return c end @@ -1034,6 +1085,10 @@ function multi:getThreads() return threads end +function multi:getTasks() + return self.Mainloop +end + function thread.request(t,cmd,...) thread.requests[t.thread] = {cmd,{...}} end diff --git a/test.lua b/test.lua index 4662f1d..b29e322 100644 --- a/test.lua +++ b/test.lua @@ -1,8 +1,32 @@ package.path = "./?/init.lua;"..package.path multi, thread = require("multi"):init() +local proc = multi:newProcessor("Test") +local proc2 = multi:newProcessor("Test2") +local proc3 = proc2:newProcessor("Test3") + function multi:getTaskStats() - local stats = {} + local stats = { + [multi.Name] = { + threads = multi:getThreads(), + tasks = multi:getTasks() + } + } + local procs = multi:getProcessors() + for i = 1, #procs do + local proc = procs[i] + stats[proc:getFullName()] = { + threads = proc:getThreads(), + tasks = proc:getTasks() + } + end + return stats end -multi:mainloop() \ No newline at end of file +local tasks = multi:getTaskStats() + +for i,v in pairs(tasks) do + print("Process: "..i) +end + +--multi:mainloop() \ No newline at end of file