Mutithreaded LWJGL - Works... Sometimes

I’m trying to implement two OpenGL contexts on different threads, all is well so-far but after glfwInit is called I get a dump file. It works flawlessly sometimes, and other times it gives me this file (summarized)

Java Threads: ( => current thread )
  0x00007fc9c823f800 JavaThread "Timer-0" [_thread_blocked, id=2248, stack(0x00007fc99693c000,0x00007fc996a3d000)]
  0x00007fc9c823d800 JavaThread "pool-1-thread-2" [_thread_in_native, id=2247, stack(0x00007fc996a3d000,0x00007fc996b3e000)]
=>0x00007fc9c823c000 JavaThread "pool-1-thread-1" [_thread_in_native, id=2246, stack(0x00007fc996b3e000,0x00007fc996c3f000)]
  0x00007fc9c81d4000 JavaThread "Monitor Ctrl-Break" daemon [_thread_in_native, id=2243, stack(0x00007fc99715f000,0x00007fc997260000)]
  0x00007fc9c80d5000 JavaThread "Service Thread" daemon [_thread_blocked, id=2241, stack(0x00007fc99756a000,0x00007fc99766b000)]
  0x00007fc9c80bf800 JavaThread "C1 CompilerThread3" daemon [_thread_blocked, id=2240, stack(0x00007fc99766b000,0x00007fc99776c000)]
  0x00007fc9c80bb000 JavaThread "C2 CompilerThread2" daemon [_thread_blocked, id=2239, stack(0x00007fc99776c000,0x00007fc99786d000)]
  0x00007fc9c80b9800 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=2238, stack(0x00007fc99786d000,0x00007fc99796e000)]
  0x00007fc9c80b6800 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=2237, stack(0x00007fc99796e000,0x00007fc997a6f000)]
  0x00007fc9c80b4800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=2236, stack(0x00007fc997a6f000,0x00007fc997b70000)]
  0x00007fc9c808c800 JavaThread "Finalizer" daemon [_thread_blocked, id=2228, stack(0x00007fc997cfd000,0x00007fc997dfe000)]
  0x00007fc9c8088000 JavaThread "Reference Handler" daemon [_thread_blocked, id=2226, stack(0x00007fc997dfe000,0x00007fc997eff000)]
  0x00007fc9c800b000 JavaThread "main" [_thread_in_Java, id=2205, stack(0x00007fc9d224e000,0x00007fc9d234f000)]

The one it’s pointing to is a thread created by the ExecutorService. Here’s the java frames:

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  org.lwjgl.glfw.GLFW.nglfwInit()I+0
j  org.lwjgl.glfw.GLFW.glfwInit()I+12
j  ecumene.astro.view.common.gl.GLView.run()V+21
j  ecumene.astro.view.ASViewStepWorker.run()V+4
j  java.util.concurrent.ThreadPoolExecutor.runWorker(Ljava/util/concurrent/ThreadPoolExecutor$Worker;)V+95
j  java.util.concurrent.ThreadPoolExecutor$Worker.run()V+5
j  java.lang.Thread.run()V+11
v  ~StubRoutines::call_stub

It’s glfwInit that’s causing these errors, and I hardly know why it does. (My best guess is that I’m not destroying objects correctly, or not allocating enough memory… either way native code usually breaks because of memory stuff :stuck_out_tongue: )

Here’s the run method, which is pretty unimpressive (I really just threw it together with some stuff I found online, it worked for a little while, then the glfwInit started crashing the VM)

@Override
public void run() {
    super.run();
    glfwPollEvents();

    glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() {
        @Override
        public void invoke(int error, long description) {
            System.err.println("glerror occurred: " + error);
        }
    });
    if (glfwInit() != GL_TRUE) {
        System.err.println("Error initializing GLFW");
    }

    windowID = glfwCreateWindow(640, 480, "My GLFW Window", NULL, NULL);

    if (windowID == NULL) {
        System.err.println("Error creating a window");
    }

    glfwDefaultWindowHints();
    glfwWindowHint(GLFW_SAMPLES, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    glfwMakeContextCurrent(windowID);

    GLContext.createFromCurrent();
    glfwSwapInterval(1);

    float now, last, delta;

    last = 0;

    init();

    while (glfwWindowShouldClose(windowID) != GL_TRUE) {
        now = (float) glfwGetTime();
        delta = now - last;
        last = now;

        update(delta);
        render(delta);

        glfwPollEvents();
        glfwSwapBuffers(windowID);
    }

    dispose();
}

I’m still very new to concurrent programming (hence the use of executorservice) but any pointers to how I may have broken this are very helpful!

I found my error, no GLFW context in the main thread.
It’s 12:40AM, Goodnight everyone :emo:

Edit: If you blew any significant time on this thread, I’m deeply sorry

You cannot call glfwPollEvents before glfwInit. If glfwSetErrorCallback was above the glfwPollEvents call, you’d see the error.

Also, calling glfwInit and handling the event loop in arbitrary threads is not supported. The design of GLFW is similar to AWT/Swing/JavaFX; event processing must happen in a single thread. See the Threads sample for the correct way to handle multiple windows/threads.

I was looking for a tutorial like that! I’m implementing the countdown and a bunch of other stuff now.

I meant to ask, does input handling per window still work regardless of the main thread?

[quote=“Ecumene,post:4,topic:56930”]
Note that you don’t have to use a CountDownLatch for synchronization/communication, that’s just an example. The only important detail is: most GLFW functions are called from the main thread, the per-window threads only deal with rendering.

This does imply that, at some point, you have to have synchronization points and/or pass messages between threads. Neither GLFW nor LWJGL have any special requirements for how that happens, it’s entirely up to the application and how it’s designed. Fortunately, Java has a very rich set of concurrency primitives (like CountDownLatch) and concurrent data structures that can be used for that purpose.

[quote=“Ecumene,post:5,topic:56930”]
The only thread that deals with window/input events is the main thread. It works fine regardless of how many windows or rendering threads you have.

I was primarily using the Countdown latch to wait for the threads to finish closing before closing the main one, but it seems like the executor service does this for me…

If the main thread deals with the window/input events what will happen if I add a glfw key callback to the child threads? Will they still be called back, or do I have to track which window is focused myself?

[quote=“Ecumene,post:7,topic:56930”]
You can’t, glfwSetKeyCallback can only be called from the main thread. The same is true for glfwPollEvents, so all events will be handled on the main thread too. If a rendering thread needs to know whether it’s corresponding window is focused or not, you must pass that information from the main thread to the rendering thread.

I recommend you look at the GLFW documentation. For each function, it gives you all the relevant info you need on thread safety. For example, from the docs for glfwCreateWindow: