# Interrupt \`Threads.@threads\` computation

**URL:** <https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199>\
**Category:** General Usage\
**Tags:** multithreading, task, threads\
**Created:** [November 9, 2021, 10:27am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199 "2021-11-09T10:27:08Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [November 9, 2021, 10:27am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/1 "2021-11-09T10:27:08Z")

</div>

I sometime deal with very lengthy computation that I would like to interrupt before they finish.  
I can achieve this by wrapping the function with `@async` and then throw an `InterruptException()` to the task when I want it to end.

Unfortunately, this does not seem to work if my function uses multithreading via `Threads.@threads` internally as I believe @threads spawn other tasks that keep going when I interrupt the originating task.

Is there a way to exploit multithreaded for with the possibility of killing the computation all-together?

---

<div class="post-metadata">

**Author:** ![disberd](https://avatars.discourse-cdn.com/v4/letter/d/8edcca/32.png) [@disberd](https://discourse.julialang.org/u/disberd)\
**Post date:** [November 10, 2021, 7:30am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/2 "2021-11-10T07:30:11Z")

</div>

For whoever might get in the same situation, I managed to hack my way out of it for a quick fix.

I was just trying some simple toy example like with the commands in this code

```julia
function testfunc()
	portion = zeros(Int,Threads.nthreads())
	Threads.@threads for i ∈ 1:400
		rand(1000,1000)*rand(1000,1000)
		portion[Threads.threadid()] += 1
		iter = sum(portion)
		mod(iter,10) === 0 && (println("iter = $iter, Thread = $(Threads.threadid())"); sleep(0.1))
	end
end

tt = @async testfunc()

schedule(tt, InterruptException();error=true)

```

Where you’ll see that after scheduling the interrupt exception the threads continue to print the status via println.

I had a look at the code of Threads.@threads and I could get thread interruptions by modifying sligthly the function at [https://github.com/JuliaLang/julia/blob/d279aede19db29c5c31696fb213e3101e2230944/base/threadingconstructs.jl#L25-L43](https://github.com/JuliaLang/julia/blob/d279aede19db29c5c31696fb213e3101e2230944/base/threadingconstructs.jl#L25-L43)

so after overwriting that method with

```julia
@eval Threads function threading_run(func)
    ccall(:jl_enter_threaded_region, Cvoid, ())
    n = nthreads()
    tasks = Vector{Task}(undef, n)
    for i = 1:n
        t = Task(func)
        t.sticky = true
        ccall(:jl_set_task_tid, Cvoid, (Any, Cint), t, i-1)
        tasks[i] = t
        schedule(t)
    end
    try
        for i = 1:n
            wait(tasks[i])
        end
	catch ex
		if isa(ex, InterruptException)
			println("InterruptException received, stopping @threads tasks!")
			map(tasks) do t
				schedule(t,InterruptException();error = true)
			end
		end
    finally
        ccall(:jl_exit_threaded_region, Cvoid, ())
    end
end

```

to add the sub-thread interruption in the catch statement, the threads are properly shut down when sending an exception.

This is serious type piracy so I suppose I should create a separate macro with basically the Threads.@threads code copy pasted with the extra `catch` modification above in a real use case.

Is there any specific reason why the multithreaded call does not already try to shut down the threads it spawned when it is interrupted?

Edit: Had some more discussion on zulip ([this thread](https://julialang.zulipchat.com/#narrow/stream/225542-helpdesk/topic/Interrupt.20.60Threads.2E.40threads.60.20computation/near/260955273)) where some drawbacks of the method above are pointed out.

---

<div class="post-metadata">

**Author:** ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)\
**Post date:** [April 19, 2023, 7:13am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/3 "2023-04-19T07:13:02Z")

</div>

I’m saddened by the fact that this obvious and painful issue has still no solution. It is crazy how I can’t terminate background threads without killing the whole REPL, thus losing precious data and computation results and having to start all over again.

A nice solution would be well appreciated.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [April 21, 2023, 8:24am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/4 "2023-04-21T08:24:32Z")

</div>

I made this:

```julia
strategy_search(trials_db, instances, data)
	REQUESTS = length(instances)
	l = ReentrantLock()
	p = Progress(REQUESTS)

	stop_cond::Bool = false	
	try
		@threads for strategy in instances
			strategy in keys(trials_db) && continue
			stop_cond && (break)
			loss = eval_strategy(strategy, data)
			lock(l) do
				trials_db[strategy] = loss
				next!(p)
			end
		end
	catch e
		stop_cond = true
		println("We stop all threads with flag. $e")
		!(e isa InterruptException) && rethrow(e)
	end
end

```

I think it is pretty simple and ultimate.  
The problem is that stop\_cond is `Core.Box` type and I hate that. But I believe it shouldn’t make too big performance drawback?

trials\_db is a simple dict that I load&save (persist) between runs: `Dict{MyStrategy, Float32}()`  
instances are just generated trials, that has to be tested.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [April 21, 2023, 11:15am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/5 "2023-04-21T11:15:43Z")

</div>

I think you should update `stop_cond` atomically, otherwise you have a data race.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 21, 2023, 12:16pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/6 "2023-04-21T12:16:23Z")

</div>

The solution is to incorporate some point in your computation where it checks for a stopping condition, cleans up or invalidates the state, and then stops the computation.

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [April 24, 2023, 6:15am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/7 "2023-04-24T06:15:48Z")

</div>

You can make it atomic if you don’t want to do any more computation or avoid any dirty read.  
For me it doesn’t matter if there is 4-30 more computation with dirty read on `stop_cond` as I am just interrupting the next 10 million computation which is the key. Also we mustn’t forget that the computations are whole so the results from each dirty read case is valid and are saved in the `trials_db`, so I can already work with ready computations perfectly.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 24, 2023, 12:17pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/8 "2023-04-24T12:17:01Z")

</div>

have a look here for an [@stoppable](https://github.com/louisponet/Trading.jl/blob/7fc902c91b3f5653c420011fc28a9fd4e4bc176f/src/utils.jl#L59-L100) macro.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 24, 2023, 1:00pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/9 "2023-04-24T13:00:22Z")

</div>

There are other similar recent threads, for instance this one: [How to early return from inside a @threads loop - #7 by lmiq](https://discourse.julialang.org/t/how-to-early-return-from-inside-a-threads-loop/97457/7)

Personally, if the condition in the final thread is not an error, I would not use a `try` block. As in the example above, I prefer to control the tasks per thread and terminate them cleanly by using a flag (atomic or locked).

---

<div class="post-metadata">

**Author:** ![Marcell\_Havlik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcell_havlik/32/37424_2.png) [@Marcell\_Havlik](https://discourse.julialang.org/u/Marcell_Havlik)\
**Post date:** [April 26, 2023, 5:03am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/10 "2023-04-26T05:03:57Z")

</div>

We are talking about `InterruptException`, so it is not error in that sense, just interrupt signal (CTRL + C), that can be handled with try-catch. So our cases are all about a very long unintended run that we want to stop manually without restarting the REPL.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [April 26, 2023, 3:39pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/11 "2023-04-26T15:39:45Z")

</div>

Should that macro (or other candidate?) have its own package (or be in Base)? It’s an obscure package, or I wouldn’t be looking there…

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 26, 2023, 3:41pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/12 "2023-04-26T15:41:51Z")

</div>

Yea it was something that I’ve just used there and in some of my packages that depended on it. I’m not sure where things like this would belong but it certainly is very useful. Maybe there should exist some curated general “Utils” package that could also be a good testing ground for things that could eventually be picked up into Base

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [April 26, 2023, 3:54pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/13 "2023-04-26T15:54:12Z")

</div>

I don’t know of a general Utils package where this would apply (there are many, but this seems to specific), except maybe at (though you would want to work for Base threads (then not the best fit there?), or both, but also maybe useful for you to know of this rather and use?):

> Polyester.jl is a Julia package that provides low overhead threading. The primary API is @batch, which can be used in place of Threads.@threads.

From Bing (ChatGPT), it didn’t know of the above, until I asked it about it the right way (had to clarify by adding .jl to the package name), then also generated the above, both it and with sources:

> ThreadsX.jl However, there are also packages that can be used to extend its functionality such as ThreadPools.jl and FLoops.jl. ThreadPools.jl exposes a few macros and functions that mimic Base.Threads.@threads, Base.map, and Base.foreach. FLoops.jl provides a simple GPU executor and @reduce syntax for supporting complex reduction in a forward-compatible manner.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [April 28, 2023, 10:43am UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/14 "2023-04-28T10:43:22Z")

</div>

I see it’s about a Task (coroutine) vs Thread (from my memory not interoperable). These are I think related, but do you know if either or both are based on `pthread`s:

[https://man7.org/linux/man-pages/man3/pthread\_cancel.3.html](https://man7.org/linux/man-pages/man3/pthread_cancel.3.html)

and if have similar support to asynchronous and deferred explained there?

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [April 28, 2023, 12:39pm UTC](https://discourse.julialang.org/t/interrupt-threads-threads-computation/71199/15 "2023-04-28T12:39:01Z")

</div>

You’re totally right. As far as I understand it is that a task is kinda like a coroutine, and it can or can not be ran by different threads. I.e. if you do `@task` and `schedule()` it will run on the thread from which you called the `schedule`. If you call `@spawn` you tell julia to run it on whatever thread is available.

Actually looking at the [@spawn](https://github.com/JuliaLang/julia/blob/ee7538e368bc33f08902bec26bf0b6b37c81d428/base/threadingconstructs.jl#L349-L387) definition is quite illuminating. It creates the task, sets where the task is allowed to run and then schedules the task.

I don’t know really whether it’s a pthread or jthread or anything like that but afaik you should not think of “stopping threads” rather stopping a task that’s running on a thread, the thread will go its merry way and run another task after interrupting it like above.
