Ups, sometimes it is the easiest stuff which one oversees. After several hours of trying different solutions for my task I finally made a trivial mistake Thanks…
EDIT: the answer was to use @async for the throwto.
One more thing here, when I try to call the function through a toggle in a Blink window, the turning on works but turning off does not. It freezes and the REPL becomes irresponsible.
Here is the code
using Blink
using Interact
const run_toggle = toggle(label = "run") |> onchange
const timer = Observable(0.0)
function switch_timer(switch)
if switch
global t = @async while true
sleep(1 / 20)
timer[] += 1 / 20
end
return
else
@async Base.throwto(t, InterruptException())
return
end
end
on(switch_timer, run_toggle)
widget = vbox(hbox(run_toggle))
window = Window()
body!(window, widget)
Yes, that might work sometimes, but you’re messing with the internal state of the scheduler, so it’s not really safe. But you’re just controlling the wrong object: sleep is just a thin wrapper around Timer and the Timer object does support start and stop (actually it maybe just exports the new and close actions right now, but it could export the start and stop names too).
In this case using start and stop would be great, thanks… However, I would also like to have a possibility to stop a general task without throwing an InterruptExeption which looks a bit awkward to me here.
Unlike Base.throwto, schedule is a public API. If it is not safe to use, could you document this? From its docstring, I think it’s impossible for users (like me) to know that it’s an unsafe API:
That’s true, it lacks a mention that only the owning queue responsible for managing that task should call that method (and calling that method transfers ownership to a new queue)
Right, if you just made the task, that’s an example of when you own it. You also usually own current_task() (which is good, because wait and yield etc. will implicitly take ownership of it), so you can also de-schedule yourself (e.g. call wait()), or throw exceptions (schedule(error=true); wait(), or, erm, throw()), and implement alternate schedulers (i.e. call wait on something that’s not a Condition object)
When you schedule an InterruptException() you silently interrupt the wait of the watch_task async task but not the watch_task task that outlives watch_folder.
This is a simplified version that shows the same issue:
function watch_task()
while true
@info "doing something ..."
sleep(3)
end
end
function watch_folder()
t = @async watch_task()
try wait(t) catch; end
end
task = @async watch_folder()
sleep(5)
schedule(task, InterruptException(), error=true)
Eventually consider to open a BetterFileWatchingIssue.jl github issue …