0

I'm working on some sensitive LWJGL code and need to make sure that I create my display, and therefore GL context before executing any other code.

To give a clear example of my current predicament, take the following:

public static void main(String[] args) {
    GLDisplay display = new GLDisplay();
    display.start();

    GLShader shader = new StaticShader();
}

The beginning of my GL creation happens in display.start(), where a separate thread is created, and within the separate thread, my Display is created.

Except this is where the problem lies, I have it in a separate thread. So then my program goes on and starts prematurely executing the new StaticShader() which calls even more GL code, breaking the program. (Can't execute before display is created).

What I'm trying to do, is achieve two threads simultaneously which I already have, but make sure that start() method is called completely before anything else is.

Here is how the start method works:

public synchronized void start() {
    Threader.createThread(this, "GLDisplay");
}

@Override  // public class GLDisplay extends Runnable
public void run() {
    // GL code goes here.
}

And here is Threader:

public static void createThread(Runnable behaviour, String name) {
    new Thread(behaviour, name + behaviour.hashCode()).start();
}

Now you may notice the synchronized keyword in the start method, well thats just one attempt I've had to no avail. I've also tried the following (which I actually grabbed from another StackOverflow answer):

@Override
public void run() {
    synchronized(this) {
        // GL code
    }
}

I've checked other StackOverflow answers but either don't understand them or don't help me in my case. With the first code block I give in the main method, that is how I want my code to look to the person using it. I'm trying to put the thread-creation inside GlDisplay to hide it.
Any ideas?

Edit:

I can't simply wait for GLDisplay to close either (with Thread.join()) because there lies a while-loop that updates the display for the entirety of the program.
This is the entire reason I multi-threaded it. To allow this forever-ending loop to run while I do other things in the program. By closing the thread, I close the loop, cleanup the display and free the GL context from memory, once again making the shader code fail for lack of an existing context.

  • If you need it to run sequentially, why do you run it in a separate thread then? – QBrute Jul 11 '17 at 03:11
  • @QBrute Well I want all my GL components stored in the main thread, and then entered into the Display thread when required. Therefore, by creating a Display, I create the second thread, where **later on** the components can be added in 'on-the-go'. –  Jul 11 '17 at 03:13
  • Can you just pass the shader instance into the display? – Michael Markidis Jul 11 '17 at 03:14
  • @MichaelMarkidis I had it set up like that in the past, but based on the work I'll be doing, it has to be completely object-based where I can have instances initialised anywhere, instead of calling a `createShader(GLShader shader)` method, etc. –  Jul 11 '17 at 03:15
  • @MichaelMarkidis Even if I passed it in, it would be passed before the display finished creating itself. (Separate thread) –  Jul 11 '17 at 03:16
  • All the gl operations should be run in the same thread. Everything else, unless very specific requirements, is a design error. – elect Jul 11 '17 at 13:28

3 Answers3

1

You can use java.util.concurrent.CountDownLatch to achieve it which aids in making a thread(s) wait till the operations on other threads is complete. Please see the reference on on what and how to use it.

Example:

public static void main(String[] args) {

    CountDownLatch cdl = new CountDownLatch(1);

    // pass the CountDownLatch into display
    GLDisplay display = new GLDisplay(cdl);
    display.start();

    // wait for the latch to have been counted down in the disp thread
    try
    {
        cdl.await();
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }

    GLShader shader = new StaticShader();
}

In your GLDisplay thread, call the countDown method of CountDownLatch

Michael Markidis
  • 4,163
  • 1
  • 14
  • 21
OTM
  • 656
  • 5
  • 8
  • Ooo, just the beginning of the JavaDoc explains **just** what I need. Let me read this, I won't be a moment. :) –  Jul 11 '17 at 03:38
  • Uhh hang on. Wouldn't this require me to store my shader object within a secondary thread? I need to keep it within the main thread of the program like I have done. –  Jul 11 '17 at 03:40
  • There is no need to keep the shader in the secondary thread. Only need to pass the latch to the secondary thread.. And you can call the contDown() method on the latch on the secondary at any point in execution to indicate the main thread to start resuming.. – OTM Jul 11 '17 at 03:44
  • Can you please show me an example then? I'm looking at the JavaDoc and relevant examples and they seem to use multiple secondary-threads irrelevant to the main. –  Jul 11 '17 at 03:45
  • Please see also for example : http://www.java67.com/2015/06/java-countdownlatch-example.html?m=1 – OTM Jul 11 '17 at 03:49
  • Thankyou for the example but you need to update your answer with the said relevant example. If the website goes down, that is gone. –  Jul 11 '17 at 03:50
  • I added in a relevant example. – Michael Markidis Jul 11 '17 at 03:52
  • @MichaelMarkidis Thanks Michael, however can I somewhat store the latch inside of the `start()` method instead, so implementations don't require building your own latch? –  Jul 11 '17 at 03:57
0

I might be misunderstanding something, but try the following:

public static void createThread(Runnable behaviour, String name) {
    Thread t = new Thread(behaviour, name + behaviour.hashCode()).start();
    t.join();
}

By calling join() the program should wait for the thread to complete.

Eduardo
  • 277
  • 1
  • 6
  • 17
  • Uhh no! That display thread is my entire window! Without it, the program will cease to exist. I probably should of said that I have a main-loop that runs within that thread for the **entirety** of the program-cycle. Pardon me. –  Jul 11 '17 at 03:25
  • If that thread closes, then the GL context is once again lost. –  Jul 11 '17 at 03:25
  • Oh I see, I guess I'm a bit confused and I'm sorry I could not be of much help. So what you actually need is the `Threader` **separated** thread within the display thread to complete before the program moves on? – Eduardo Jul 11 '17 at 03:41
  • I want the separate thread to still exist. There won't be any completion of the thread. I'm trying to get the `start()` method to complete, or rather a certain portion of it, which then resumes every other thread. –  Jul 11 '17 at 03:42
  • After that *certain portion* is completed, `start()` is still working through the rest of its own method, but the other threads resume too. –  Jul 11 '17 at 03:43
  • I updated my answer to reflect what I was thinking but keeping the same reasoning, I understand it might not be the solution still, but now I'm interested and I'll keep looking into it and maybe create a LWJGL code to test it out better. – Eduardo Jul 11 '17 at 03:57
  • Thanks for that. Still a little bit off, but I appreciate your help anyhow! :) –  Jul 11 '17 at 03:58
0

Well I remember now that I can't have GL code against two separate threads anyway, but thats besides the point.

I don't actually need to use any thread-lock classes or anything, but rather can just do something as simple as this:

private Boolean threadLock = true;
public void start() {
    Threader.createThread(this, "GLDisplay");
    while (true) {
        synchronized(threadLock) {
            if (!threadLock) break;
        }
    }
}

@Runnable
public void run() {
    // Do GL code.
    synchronized(threadLock) { threadLock = false; }
    // Do the rest of whatever I'm doing.
}

When the threadlock is reached in the second thread and is released, the first thread continues doing it's activity. It's that simple!

  • 1) It's not best practice to synchronize on boolean: https://stackoverflow.com/questions/10324272/why-is-it-not-a-good-practice-to-synchronize-on-boolean 2) Why use the busy wait loop and spin unnecessarily? I would just use the CountDownLatch from @OTM answers in this context. – Michael Markidis Jul 11 '17 at 14:42
  • @MichaelMarkidis Of course, I want to use them except found no way to use them without having to incorporate within the main method. This method simply *hides* it, and can therefore be used in a library without needing the user to implement it themselves. I'm still looking at it though, I don't like the boolean way, its too dirty. –  Jul 12 '17 at 04:20
  • What I was saying is that you can still use the CountDownLatch internally in this class. Just use the latch instead of the `threadLock` – Michael Markidis Jul 12 '17 at 04:28
  • @MichaelMarkidis AH! Pardon me. I see what your getting at now! Place the instance within the class instead. That's going to be so much better. Thankyou. –  Jul 12 '17 at 04:31