# GC problems with \`jl\_gc\_unsafe\_enter\` with multithreaded embedding

**URL:** <https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467>\
**Category:** General Usage\
**Tags:** embedding, garbage-collection, java\
**Created:** [October 1, 2023, 2:49pm UTC](https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467 "2023-10-01T14:49:31Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Keluaa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keluaa/32/50675_2.png) [@Keluaa](https://discourse.julialang.org/u/Keluaa)\
**Post date:** [October 1, 2023, 2:49pm UTC](https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467/1 "2023-10-01T14:49:31Z")

</div>

I am currently developping a Kotlin library to embed Julia in the JVM, with the goal to support multithreading with `jl_adopt_thread()`. The main issue is that when using some frameworks, there may not be a way to be in control of which JVM thread would want to use Julia.

If Julia is used through JVM worker threads, then you would want to make sure that after the work is done, the adopted JVM thread does not prevent the GC from running: good management of the thread’s `gc_state` is required.

What I came up with is the following code (simplified):

```plaintext
fun runUsingJulia(func: () -> Unit) {
    var wasThreadAdopted = false
    if (!isThreadAdopted()) {
        jl_adopt_thread()
        wasThreadAdopted = true
    }

    val oldState = jl_gc_unsafe_enter()
    try {
        func()
    } finally {
        jl_gc_unsafe_leave(oldState)
        if (wasThreadAdopted) {
            jl_gc_safe_enter()
        }
    }
}

```

Then `runUsingJulia(someFunction)` would:

- Adopt the current thread if needed
- Mark the current thread as running Julia code (GC unsafe)
- Run `someFunction`
- Mark the current thread as GC safe (`jl_gc_safe_enter` is needed as `jl_adopt_thread` marks the thread as GC unsafe by default, and therefore must be called once)

**However, this is not robust, as `jl_gc_unsafe_enter` will segfault if the GC is running.**  
[The first lines of `jl_adopt_thread`](https://github.com/JuliaLang/julia/blob/64fc7db055604a8858e38e18bd81ff14f8f45101/src/threading.c#L416-L419C6) show how to deal with a similar edge-case, but:

- `jl_gc_running` is not exported: it is not possible to know if it is safe to call `jl_gc_unsafe_enter` beforehand
- `jl_gc_disable_counter` is not exported: there is no way to prevent the GC from starting before we call `jl_gc_unsafe_enter` (writes should also be atomic, which is not possible within the JVM)
- `jl_safepoint_wait_gc` would be a good way to wait for the GC to finish (plus dealing with another edge-case where the thread is marked as GC unsafe and the GC is currently waiting for it), but it is not exported

Therefore I cannot use those from Kotlin to prevent `jl_gc_unsafe_enter` to segfault.

Is there any way to adopt threads for temporary work with Julia without preventing GC and edge-cases?

I should mention that I managed to make this work reliably in Windows, where `jl_gc_running` and `jl_safepoint_wait_gc` are accessble for some reason. Obviously, supporting all platforms would be better.

---

<div class="post-metadata">

**Author:** ![bmmogensen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bmmogensen/32/206516_2.png) [@bmmogensen](https://discourse.julialang.org/u/bmmogensen)\
**Post date:** [January 25, 2024, 9:33am UTC](https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467/3 "2024-01-25T09:33:36Z")

</div>

Hi Keluaa,

Thanks for the interesting post. I’ve been working on a similar problem integrating C++ threads using jl\_adopt\_threads, and while I don’t have a solution I have the following observations from Julia 1.10:

- jl\_gc\_unsafe\_enter() / jl\_gc\_unsafe\_leave() / jl\_gc\_safe\_enter() used as above works on Windows but not on Linux as a thread ends up in a jl\_gc\_wait\_for\_the\_world() which halts execution
- jl\_gc\_running() and jl\_safepoint\_wait\_gc() are not exposed on Windows any longer

On Linux I currently resolve to our old ways of using a single C++ thread to perform all calls to Julia, but on Windows I seem to be able to make use of the jl\_adopt\_thread() and use threading. But I’m looking out for segfaults and other strange behavior.

/Bjorn

---

<div class="post-metadata">

**Author:** ![Keluaa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keluaa/32/50675_2.png) [@Keluaa](https://discourse.julialang.org/u/Keluaa)\
**Post date:** [January 25, 2024, 9:39am UTC](https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467/4 "2024-01-25T09:39:14Z")

</div>

Thank you, it reassures me that I am not the only one who stumbled on this problem, which made me give up on using Julia from Kotlin.

I think that most of the work around `jl_adopt_thread` was done to embed multi-threaded applications from Julia, and not the opposite, which is what we want here.

Looking at recent commits to `src/threading.c`, [this addition](https://github.com/JuliaLang/julia/commit/3f23533f0c5436570d9bea61a49d6592c85cdc56) could solve the issue (the commit message has a lot of info), it might be worth using a nightly build to see if it could work or not.

---

<div class="post-metadata">

**Author:** ![Chrysoberyl](https://avatars.discourse-cdn.com/v4/letter/c/ed655f/32.png) [@Chrysoberyl](https://discourse.julialang.org/u/Chrysoberyl)\
**Post date:** [January 30, 2026, 7:39am UTC](https://discourse.julialang.org/t/gc-problems-with-jl-gc-unsafe-enter-with-multithreaded-embedding/104467/5 "2026-01-30T07:39:26Z")

</div>

You can setup your own condition variable via `jl_gc_set_cb_pre_gc` and `jl_gc_set_cb_post_gc`. This pair of functions are executed with certainty with each `jl_gc_collect` call
