Java OpenGL - 线程挂起它不应该

时间:2015-03-05 13:10:49

标签: java multithreading opengl lwjgl

我一直在关注另一个java游戏开发教程,以便对线程有一个基本的了解,我已经学习了these教程并将它们与我之前学到的openGL编程相结合。除了我认为我可能错过了一些内容,因为在调用engine.stop()(包括thread.join())时,窗口关闭,程序在后台挂起,你必须结束它的过程。

这是我的代码:

package com.daboom.threadgl;

import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

import com.daboom.threadgl.graphics.Camera;

public class EngineMain implements Runnable {

    private boolean running;
    private Thread thread;
    private Camera cam;


    /**
     * Starts the Dual Threaded System, does not need to be called, 
     * already called upon application beginning
     */
    @Override
    public void run() {
        initDisplay();
        long lastTime = System.nanoTime();
        long timer = System.currentTimeMillis();
        final double ns = 1000000000.0 / 60.0;
        double delta = 0;
        int frames = 0;
        int updates = 0;
        while (running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                update();

                updates++;
                delta--;
            }

            render();
            if (Display.isCloseRequested())
                break;
            frames++;

            if (System.currentTimeMillis() - timer > 1000) {
                timer += 1000;
                System.out.println(updates + " u/sec " + frames + " f/sec");
                Display.setTitle(Game.gameName + " || " + updates + " u/sec " + frames
                        + " f/sec ||");
                updates = 0;
                frames = 0;
            }

        }
        stop();
    }

    private void update() {
        game.update();
    }

    Game game;

    private void render() {
        GL11.glLoadIdentity();
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        cam.useView();
        game.render3D();
        cam.setProjection2D(Display.getWidth(), Display.getHeight());
        game.render2D();
        Display.update();
        cam.resetTo3D();
    }

    public EngineMain() {
        cam = new Camera();
        game = new Game(this, cam);
    }

    private void initDisplay() {
        try {
            Display.setDisplayMode(new DisplayMode(800, 600));
            Display.setTitle(Game.gameName);
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }

        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glClearColor(0, 0, 0, 1);
        cam.setProjection3D(63,(float) Display.getWidth() / (float)Display.getHeight(), 0.3f,
                1000);


        try {
            Keyboard.create();
            Mouse.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }
    }

    /**
     * Starts the Multi-Threading and the Game
     * 
     */
    public synchronized void start() {
        running = true;
        thread = new Thread(this, "Display");
        thread.start();
    }
    /**
     * Safely Stops the program
     * Call this to exit the game
     */
    public synchronized void stop() {
        running = false;
        Mouse.destroy();
        Keyboard.destroy();
        Display.destroy();

        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

}

当我使用他的教程,没有使用他的代码的修改时,过程正确结束。

我无法为我的生活找到问题。

如果您需要更多评论,请询问。

编辑:这是修改前的原始代码

package com.thecherno.rain;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

import com.thecherno.rain.graphics.Screen;
import com.thecherno.rain.input.Keyboard;

public class Game extends Canvas implements Runnable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public static int width = 300;
    public static int height = width / 16 * 9;
    public static int scale = 3;
    public static String title = "Rain";
    private Thread thread;
    private JFrame frame;
    private Keyboard key;
    private boolean running = false;

    private Screen screen;

    private BufferedImage image = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_RGB);
    private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer())
            .getData();

    public Game() {
        Dimension size = new Dimension(width * scale, height * scale);
        setPreferredSize(size);
        screen = new Screen(width, height);
        frame = new JFrame();
        key = new Keyboard();
        addKeyListener(key);
    }

    public synchronized void start() {
        running = true;
        thread = new Thread(this, "Display");
        thread.start();
    }

    public synchronized void stop() {
        running = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void run() {
        long lastTime = System.nanoTime();
        long timer = System.currentTimeMillis();
        final double ns = 1000000000.0 / 60.0;
        double delta = 0;
        int frames = 0;
        int updates = 0;
        while (running) {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1) {
                update();
                updates++;
                delta--;
            }
            render();
            frames++;

            if (System.currentTimeMillis() - timer > 1000) {
                timer += 1000;
                System.out.println(updates + " u/sec " + frames + " f/sec");
                frame.setTitle(title + " | " + updates + " u/sec " + frames
                        + " f/sec");
                updates = 0;
                frames = 0;
            }

        }
        stop();
    }

    int x, y;

    public void update() {
        key.update();

        if (key.up)
            y--;
        if (key.down)
            y++;
        if (key.left)
            x--;
        if (key.right)
            x++;
    }

    public void render() {
        BufferStrategy bs = getBufferStrategy();
        if (bs == null) {
            createBufferStrategy(3);
            return;
        }
        screen.clear();
        screen.render(x, y);

        for (int i = 0; i < pixels.length; i++) {
            pixels[i] = screen.pixels[i];
        }

        Graphics g = bs.getDrawGraphics();
        g.fillRect(0, 0, getWidth(), getHeight());
        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        g.dispose();
        bs.show();
    }

    public static void main(String[] args) {
        Game game = new Game();
        game.frame.setResizable(false);
        game.frame.setTitle(Game.title);
        game.frame.add(game);
        game.frame.pack();
        game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        game.frame.setLocationRelativeTo(null);
        game.frame.setVisible(true);

        game.start();
    }

}

2 个答案:

答案 0 :(得分:1)

可能您的修改导致一些非守护程序线程启动。您可以在更改之前和之后使用以下方法来查看正在运行的线程

private static void dumpThreads() {
    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    for (Thread thread : threadSet) {
        System.out.println(String.format("threadName = '%s', daemon = %b",
                thread.getName(), thread.isDaemon()));
    }
}

另见:What is Daemon thread in Java?

答案 1 :(得分:0)

好的,所以我已经弄清楚了...就像BDL说的那样,我不能在活动线程中调用join,不幸的是,由于LWJGL的无情性,它需要重组主类。

供将来参考(对我和其他任何人)以下是当前代码:

package com.daboom.threadgl;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import com.daboom.threadgl.graphics.Camera;

public class EngineMain implements Runnable {

    private boolean running;
    private Thread thread;
    private Camera cam;
    public boolean isLogicThreadRunning = false;

    /**
     * Starts the Dual Threaded System, does not need to be called, already
     */
    @Override
    public void run() {
        while (running) {
            update();
            Display.sync(60);
        }
    }

    private void update() {
        game.update();
    }

    Game game;

    private void render() {
        GL11.glLoadIdentity();
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        cam.useView();
        game.render3D();
        cam.setProjection2D(Display.getWidth(), Display.getHeight());
        game.render2D();
        Display.update();
        cam.resetTo3D();
    }

    public EngineMain() {

        cam = new Camera();
        game = new Game(this, cam);

    }

    private void initDisplay() {
        try {
            Display.setDisplayMode(new DisplayMode(800, 600));
            Display.setTitle(Game.gameName);
            Display.create();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }

        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glClearColor(0, 0, 0, 1);
        cam.setProjection3D(63,
                (float) Display.getWidth() / (float) Display.getHeight(), 0.3f,
                1000);

    }

    /**
     * Starts the Game engine
     * 
     */
    public synchronized void start() {
        running = true;
        if (Runtime.getRuntime().availableProcessors() > 1) {

            thread = new Thread(this, "Update");
            thread.start();
            isLogicThreadRunning = true;

        }
        else
        {
            isLogicThreadRunning = false;
            System.out.println("WARNING: SINGLE CORE SYSTEM DETECTED, FPS LIMITED TO 60");
        }
        initDisplay();
        gameLoop();
    }

    /**
     * Stops the program. Call this to exit the game
     */
    public synchronized void stop() {
        running = false;
        System.out.println(Thread.currentThread().getName());
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // dumpThreads();
    }

    public void gameLoop() {
        while (running) {
            if (!isLogicThreadRunning) {
                update();
                Display.sync(60);
            }

            render();
            if (Display.isCloseRequested())
                running = false;
        }
    }

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

}

永远想弄清楚这一点,我仍然不知道教程中的原始代码是如何工作的,但似乎试图将LWJGL实现到它中似乎打破了它,因为openGL上下文是单线程性质。

当然,如果我正在做一些不推荐或不正确的事情,请告诉我,因为我在线程方面是业余爱好者。 (实际上,我仍然是openGL的业余爱好者...我需要一台新PC来获得最佳/新功能,感叹......仍然坚持使用3.1)