threaded functions can now be paused

This commit is contained in:
Ryan Ward 2021-07-05 22:23:45 -04:00
parent ea77b934b6
commit 9cff2735ba
3 changed files with 184 additions and 71 deletions

View File

@ -120,15 +120,84 @@ process|Thread|thread| A handle to a multi thread object
Changed:
---
- `f = thread:newFunction(func,holdme)`
- Nothing changed that will affect how the object functions defaulty. The returned function is now a table that is callable and 2 new methods have been added:
Method | Description
---|---
Pause() | Pauses the function, Will cause the function to return `nil, Function is paused`
Resume() | Resumes the function
```lua
package.path = "./?/init.lua;"..package.path
multi, thread = require("multi"):init()
test = thread:newFunction(function(a,b)
thread.sleep(1)
return a,b
end, true)
print(test(1,2))
test:Pause()
print(test(1,2))
test:Resume()
print(test(1,2))
--[[ -- If you left holdme nil/false
print(test(1,2).connect(function(...)
print(...)
end))
test:Pause()
print(test(1,2).connect(function(...)
print(...)
end))
test:Resume()
print(test(1,2).connect(function(...)
print(...)
end))
]]
multi:mainloop()
```
**Output:**
```
1 2
nil Function is paused
1 2
```
**If holdme is nil/false:**
```
nil Function is paused
1 2 nil...
1 2 nil...
```
- thread.hold(n,opt) [Ref. Issue](https://github.com/rayaman/multi/issues/24)
- Added option table to thread.hold
| Option | Description |
---|---
| interval | Time between each poll |
| cycles | Number of cycles before timing out |
| sleep | Number of seconds before timing out |
| interval | Time between each poll |
| skip | Number of cycles before testing again, does not cause a timeout! |
**Note:** cycles and sleep options cannot both be used at the same time. Cycles take priority if both are present! HoldFor and HoldWithin can be emulated using the new features. Old functions will remain for backward compatibility.
**Note:** cycles and sleep options cannot both be used at the same time. Interval and skip cannot be used at the same time either. Cycles take priority than sleep if both are present! HoldFor and HoldWithin can be emulated using the new features. Old functions will remain for backward compatibility.
Using cycles, sleep or interval will cause a timeout; returning nil, multi.TIMEOUT
- `n` can be a number and thread.hold will act like thread.sleep. When `n` is a number the option table will be ignored!

View File

@ -102,7 +102,7 @@ function multi:getTasksDetails(t)
count = count + 1
table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],v.TID})
end
for v,i in pairs(multi.PausedObjects) do
for v,i in pairs(self.PausedObjects) do
local name = v.Name or ""
if name~="" then
name = " <"..name..">"
@ -1007,6 +1007,10 @@ function thread.hold(n,opt)
dRef[2] = opt.sleep
dRef[3] = n or dFunc
return coroutine.yield(dRef)
elseif opt.skip then
dRef[1] = "_skip_"
dRef[2] = opt.skip or 1
return coroutine.yield(dRef)
end
end
if type(n) == "number" then
@ -1126,7 +1130,17 @@ local function cleanReturns(...)
return unpack(returns,1,ind)
end
function thread:newFunction(func,holdme)
return function(...)
local tfunc = {}
tfunc.Active = true
function tfunc:Pause()
self.Active = false
end
function tfunc:Resume()
self.Active = true
end
local function noWait()
return nil, "Function is paused"
end
local rets, err
local function wait(no)
if thread.isThread() and not (no) then
@ -1147,6 +1161,19 @@ function thread:newFunction(func,holdme)
return cleanReturns(rets[1],rets[2],rets[3],rets[4],rets[5],rets[6],rets[7],rets[8],rets[9],rets[10],rets[11],rets[12],rets[13],rets[14],rets[15],rets[16])
end
end
tfunc.__call = function(t,...)
if not t.Active then
if holdme then
return nil, "Function is paused"
end
return {
isTFunc = true,
wait = noWait,
connect = function(f)
f(nil,"Function is paused")
end
}
end
local t = multi.getCurrentProcess():newThread("TempThread",func,...)
t.OnDeath(function(self,status,...) rets = {...} end)
t.OnError(function(self,e) err = e end)
@ -1158,11 +1185,13 @@ function thread:newFunction(func,holdme)
wait = wait,
connect = function(f)
t.OnDeath(function(self,status,...) f(...) end)
t.OnError(function(self,err) f(err) end)
t.OnError(function(self,err) f(nil,err) end)
end
}
return temp
end
setmetatable(tfunc,tfunc)
return tfunc
end
-- A cross version way to set enviroments, not the same as fenv though
function multi.setEnv(func,env)

117
test.lua
View File

@ -2,60 +2,75 @@ package.path = "./?/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
test = thread:newFunction(function()
return 1,2,nil,3,4,5,6,7,8,9
end,true)
print(test())
multi:newThread("testing",function()
print("#Test = ",test())
print(thread.hold(function()
print("Hello!")
return false
end,{
interval = 2,
cycles = 3
})) -- End result, 3 attempts within 6 seconds. If still false then timeout
print("held")
end).OnError(function(...)
print(...)
end)
sandbox = multi:newProcessor()
for i,v in pairs(sandbox.process) do
print(i,v)
end
io.read()
sandbox:newTLoop(function()
print("testing...")
end,1)
test2 = multi:newTLoop(function()
print("testing2...")
end,1)
sandbox:newThread("Test Thread",function()
local a = 0
while true do
test = thread:newFunction(function(a,b)
thread.sleep(1)
a = a + 1
print("Thread Test: ".. multi.getCurrentProcess().Name)
if a == 10 then
sandbox.Stop()
end
end
end).OnError(function(...)
print(...)
return a,b
end)
multi:newThread("Test Thread",function()
while true do
thread.sleep(1)
print("Thread Test: ".. multi.getCurrentProcess().Name)
end
end).OnError(function(...)
print(test(1,2).connect(function(...)
print(...)
end)
end))
test:Pause()
print(test(1,2).connect(function(...)
print(...)
end))
test:Resume()
print(test(1,2).connect(function(...)
print(...)
end))
sandbox.Start()
-- test = thread:newFunction(function()
-- return 1,2,nil,3,4,5,6,7,8,9
-- end,true)
-- print(test())
-- multi:newThread("testing",function()
-- print("#Test = ",test())
-- print(thread.hold(function()
-- print("Hello!")
-- return false
-- end,{
-- interval = 2,
-- cycles = 3
-- })) -- End result, 3 attempts within 6 seconds. If still false then timeout
-- print("held")
-- end).OnError(function(...)
-- print(...)
-- end)
-- sandbox = multi:newProcessor()
-- for i,v in pairs(sandbox.process) do
-- print(i,v)
-- end
-- io.read()
-- sandbox:newTLoop(function()
-- print("testing...")
-- end,1)
-- test2 = multi:newTLoop(function()
-- print("testing2...")
-- end,1)
-- sandbox:newThread("Test Thread",function()
-- local a = 0
-- while true do
-- thread.sleep(1)
-- a = a + 1
-- print("Thread Test: ".. multi.getCurrentProcess().Name)
-- if a == 10 then
-- sandbox.Stop()
-- end
-- end
-- end).OnError(function(...)
-- print(...)
-- end)
-- multi:newThread("Test Thread",function()
-- while true do
-- thread.sleep(1)
-- print("Thread Test: ".. multi.getCurrentProcess().Name)
-- end
-- end).OnError(function(...)
-- print(...)
-- end)
-- sandbox.Start()
multi:mainloop()