Multithreading: cannot access struct member in another thread in ModernGL/GLFW app

I’m trying to play audio in another thread using WAV.jl via @Threads.spawn .
I do run julia with multiple threads via --threads parameter.
(referenced data: SnakeGameCollection/common_data at main · karna48/SnakeGameCollection · GitHub)

It works in a normal program:

import WAV

struct Sound
    fs
    y
    filename
    function Sound(filename::String)
        y, fs = WAV.wavread(filename)
        new(fs, y, filename)
    end
end

function play(sound::Sound)
    println("start playing ", sound.filename)
    WAV.wavplay(sound.y, sound.fs)
    println("end playing ", sound.filename)
end

function load_play(filename::String)
    y, fs = WAV.wavread(filename)
    WAV.wavplay(y, fs)
end

sound_die = Sound(joinpath("..", "common_data", "die.wav"))
sound_eat = Sound(joinpath("..", "common_data", "eat.wav"))

Threads.@spawn play(sound_die)

for i in 1:10
    println("main thread sleeps!")
    sleep(1)
    play(sound_eat)
end

However in my ModernGL/GLFW app it does not work, it freezes when it’s trying to access any member of Sound structure, even the filename::String. But the variant with loading the file inside the thread and then playing it works.
The minimal example:

import WAV
using ModernGL, GLAbstraction, GLFW
const GLA = GLAbstraction

struct Sound
    fs
    y
    filename
    function Sound(filename::String)
        y, fs = WAV.wavread(filename)
        new(fs, y, filename)
    end
end

function play(sound::Sound)
    println("start playing ", sound.filename)
    WAV.wavplay(sound.y, sound.fs)
    println("end playing ", sound.filename)
end

function load_play(filename::String)
    y, fs = WAV.wavread(filename)
    WAV.wavplay(y, fs)
end

g_keys = Dict()  # GLFW.GetKey did not work for me

window = GLFW.Window(name="sound not working ModernGL/GLFW", resolution=(800, 600))
GLA.set_context!(window)

glClearColor( 0.7, 0.7, 1, 0 )

GLFW.SetKeyCallback(window, (_, key, scancode, action, mods) -> begin
    if action == GLFW.PRESS
        g_keys[key] = true
    else
        g_keys[key] = false
    end
end)


sound_die = Sound(joinpath("..", "common_data", "die.wav"))
sound_eat = Sound(joinpath("..", "common_data", "eat.wav"))


while !GLFW.WindowShouldClose(window)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    GLFW.SwapBuffers(window)
    GLFW.PollEvents()

    if get(g_keys, GLFW.KEY_ESCAPE, false)
        GLFW.SetWindowShouldClose(window, true)
    end

    if get(g_keys, GLFW.KEY_P, false)
        @Threads.spawn load_play(joinpath("..", "common_data", "die.wav"))
        g_keys[GLFW.KEY_P] = false
    end

    if get(g_keys, GLFW.KEY_K, false)
        @Threads.spawn play(sound_die)
        g_keys[GLFW.KEY_K] = false
    end


    if get(g_keys, GLFW.KEY_O, false)
        @Threads.spawn load_play(joinpath("..", "common_data", "eat.wav"))
        g_keys[GLFW.KEY_O] = false
    end

    if get(g_keys, GLFW.KEY_L, false)
        @Threads.spawn play(sound_eat)
        g_keys[GLFW.KEY_L] = false
    end
   
    if get(g_keys, GLFW.KEY_SPACE, false)
        println("SPACE!")
    end
end
GLFW.DestroyWindow(window)

Can GLFW somehow change how threads can access their data?