I'm making a game in android using opengl-es, using multiple threads:
class World{
protected static final AtomicInteger entityLock = new AtomicInteger();
private GameEntity entities[];
public World(){
// populate game world with entities
// executed on main thread
addEntity(new GameEntity("tank"));
addEntity(new GameEntity("rifleman"));
addEntity(new GameEntity("rifleman"));
}
void update(){
synchronized(entityLock){
for(int i = 0;i<entities.length;i++){
// move entity to new position
// executed on PhysThread
entities[i].updatePosition();
}
}
if(entity.isDead(){
// remove entity. Enter sync block inside removeEntity() method
removeEntity(entity);
}
}
void draw(GL10 gl){
synchronized(entityLock){
for(int i = 0;i<entites.length;i++){
// draw models
// executed on GLThread
Vector3 entityPosition = entities[i].getPosition();
gl.glTranslatef(entityPosition.x, entityPosition.y, entityPosition.z);
entities[i].draw();
}
}
}
public void addEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
public void removeEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
}
class MyRenderer implements GLSurfaceView.Renderer{
World world;
public MyRenderer(World world){
this.world = world;
}
public void onDrawFrame(GL10 gl) {
// executed on GLThread
world.draw(gl);
}
}
class PhysThreadRunnable implements Runnable{
private long tickRate = 30;
private World world;
private PhysThreadRunnable(World world){
this.world = world;
}
protected void setTickRate(long tickRate){
this.tickRate = tickRate;
}
public void run() {
while(true){
try {
// executed on PhysThread
world.update();
Thread.sleep(1000/tickRate);
} catch (InterruptedException e) {
return;
}
}
}
}
MyActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
World world = new World();
// sets up the game world, populates it with entities
// set up GLSurfaceView (simplified)
setContentView(R.layout.main);
GLSurfaceView mGLView = findViewById(R.id.myGLSurfaceView);
mGLView.setRenderer(new MyRenderer(world));
// start phys thread
PhysThreadRunnable physThreadRunnable = new PhysThreadRunnable(world);
Thread physThread = new Thread(physThreadRunnable);
physThread.start();
}
}
I have a problem where sometimes (but not every time) when I start the game, the PhysThread gets stuck waiting for the lock to be released (i.e. when I go to debug and pause the thread, it is just sat on synchronized(entityLock) inside update()
What's really strange is that after a while (between 2 seconds and a minute), the PhysThread will be unblocked, and the game will continue without either thread getting locked out for more than a few iterations of the thread loops. (i.e. the game runs fine)
Edit: I added some extra stuff to the example, just in case that is the cause of the problem. Basically, updating and drawing an array of entities rather than a single entity
I think the issue here is probably that there is no fairness guaranteed by the 'synchronized' block.
The OpenGL thread will always be rendering continuously, so it will attempt to reenter onDraw as soon as it finishes it. Since the choice of which thread is allowed to enter the synchronized block is arbitrary, it could be possible that the OpenGL thread attempts to reacquire the lock before it is released to the physics thread, and based on some arbitrary criteria it is given the lock over and over without allowing the physics thread to enter.
This might explain why it happens sometime and not others, since it is an arbitrary decision.
You might try implementing a fair lock instead of a synchronization block, or making it such that the OpenGL does not attempt to redraw the scene more than once since the last physics update (put the render thread to sleep until an update has occured).
In the end, I went for the cheat solution. I put the synchronization blocks around access to the entities array and put the for loops inside a try/catch with ArrayIndexOutOfBounds:
void update(){
try{
for(int i = 0;i<entities.length;i++){
GameEntity entity = entities[i];
synchrnonized(entity){
entity.updatePosition();
}
}
}catch(ArrayIndexOutOfBoundsException aioob){
if(tryAgain){
update();
} else {
return;
}
}
}
The problem with this solution is that if entity.updateposition() throws an ArrayIndexOutOfBoundsException from something completely unrelated, then I'll catch it and misinterpret it. Plus the whole thing is a bit messy, and once in every while, a frame or update gets skipped
As this appears to solved the problem, I suspect the original cause probably lies somewhere deeper in my code, between entering the for loops and actually modifying the entities, and I don't really think it'd be fair to dump my entire code here.
I'll leave the question unanswered for a couple days in case anyone else has a better solution
Related
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.
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
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.
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!
I'm writing an application with the libgdx api for Android, and I'm running into issues concerning changing states and multithreading.
What I initially want is two asynchronous threads running at the same time, one being the game render thread, and the other being the game logic thread. I then want to be able to change the state of the game, which changes the update/render methods on their respective objects. Obviously, the render thread is running per frame (which is taken care of by libgdx already). This is my code modeling my attempt to do so:
public final class StateManager {
private static State gameState = State.START;
private static StateObject stateObject = new StartScreen();
private static final Object syncObjectUpdate = new Object();
private static final Object syncObjectRender = new Object();
public static void update(float elapsedTime){
if (!stateObject.isCreated){
//pause this thread until render thread stops
synchronized(syncObjectUpdate) {
try {
// Calling wait() will block this thread until another thread
// calls notify() on the object.
syncObjectUpdate.wait();
} catch (InterruptedException ignored) {} // Happens if someone interrupts your thread.
}
//once the render thread stops-
stateObject.dispose();
switch (gameState){
//note: creating a new object here sets isCreated to true,
//so the if statements gets called only once per state change.
case START:
stateObject = new StartScreen();
break;
case GAME:
stateObject = new GameScreen();
break;
case LOADING:
//stateObject = new LoadingScreen();
break;
default:
System.out.print("ERROR IN STATE!");
break;
}//end switch
//-change the state and resume render thread
//what if this happens before wait? surround in while loop?
synchronized(syncObjectRender) {
syncObjectRender.notify();
}
}//end if
stateObject.update(elapsedTime);
}
public static void render(){
stateObject.render();
//if update thread is waiting
if (MyGdxGame.logicThread.getState() == Thread.State.WAITING){
//then resume that one,
synchronized(syncObjectUpdate) {
syncObjectUpdate.notify();
}
// and pause this one
synchronized(syncObjectRender) {
try {
syncObjectRender.wait();
} catch (InterruptedException ignored) {}
}
}//end if
}//end render
public static void changeState(State state){
stateObject.isCreated = false;
gameState = state;
}
public static void dispose(){
stateObject.dispose();
}
public static void resize(int width, int height){
stateObject.resize(width, height);
}
public static void pause(){
stateObject.pause();
}
public static void resume(){
stateObject.resume();
}
}//class
This runs well, until I call changeState(), and it throws the error:
E/AndroidRuntime(19094): java.lang.IllegalArgumentException: Error compiling shader
I THINK this happened because stateObject.render() got called (which changes the spritebatch and such) while there was no StateObject present.
[BTW, if it isn't clear already, a StateObject is something like a start screen, or game screen, which has a render() and update() method inside that are called by two different threads. Also, I wrote this program before without multithreading, and the state changing mechanism worked perfectly.]
Here's my thought process:
1. When I change the state, the update thread gets the notification. This pauses the update thread. (Render is still running)
2. When the render thread sees that the update thread is paused, it resumes the update thread and pauses the render thread. This is so the stateObject.render() method doesn't get called before it tries to call render() on something that is disposed.
3. At this point, the update thread is notified to start up again, so it disposes of the StateObject and creates a new one.
4. Now that a new state object is initialized, stateObject.render() should have no problem. It then resumes the render thread. Both threads should be running, and peace in the universe is restored.
Now there's obviously something wrong with my implementation or that logic, because I'm getting that error. So... why?
Any help is greatly appreciated. If something isn't clear, let me know in the comments. Thanks!
Through hours of experimenting, I was able to solve this by putting the switch-case in the render method, and deleting the line stateObject.dispose();. That's it, no waiting on threads and locking objects. This now calls the appropriate render method for the state without issues of changing the spritebatch (because its in the same OpenGL thread). Deleting the dispose method means that whenever I attempt to change the state, the update method always has something to update.
This is rather a work around because changing the sate is now handed in the render method, but the performance impact is very minimal.
Here are the working render and update methods with the changes (same class):
public static void update(float elapsedTime){
stateObject.update(elapsedTime);
}
public static void render(){
stateObject.render();
if (!stateObject.isCreated){
switch (gameState){
case START:
stateObject = new StartScreen();
break;
case GAME:
stateObject = new GameScreen();
break;
case LOADING:
//stateObject = new LoadingScreen();
break;
default:
System.out.print("ERROR IN STATE!");
break;
}//end switch
}//end if
}//end render
I hope this helps someone!
I'm working on a little game (bomberman), using javafx. Basically, I have players which can plant bomb. The bomb has a duration (1500ms before explosion, for example).
So, when my player plant a bomb, I start a thread in the bomb, using a Thread.sleep(ms), and right after I notify the player that the bomb has exploded.
Thing is, my player can drop his bomb then move... But when the bomb explodes, it notify the instance of the player with the coordinate when the bomb was planted...
For example, if my player is in [2;2], plant a bomb, then move to [2;4], then the bomb explodes, my player goes back to [2;2]...
Anyone knows how could I actualize the instance of player my bomb is pointing to ... ?
Here's a sample of code :
public class Player{
public void putBomb(){
listBomb.add(new Bomb(this));
}
public void refresh(){
System.out.println(xCoordinate+" "+yCoordinate);
}
}
public class Bomb{
public Bomb(Player p){
observer=p;
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1500);
notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void sendNotification(){
observer.refresh();
}
}
As your question is JavaFX specific, the recommendations on how to do this vary from a non-GUI Java program (because JavaFX has in-built concurrency assistance and a single-threaded application programming model).
You don't need another thread, you can use a PauseTransition.
public class Bomb{
public Bomb(final Player player){
PauseTransition pause = new PauseTransition(Duration.seconds(1.5));
pause.setOnFinished(event -> player.refresh());
pause.play();
}
);
If for some reason you didn't wish to use a transition and you want to use your own threading, then you should look use JavaFX concurrency utilities such as Task.
If you didn't want to use a Task, then you can still create your own thread or runnable, but ensure that any callbacks are made using Platform.runLater(). For example:
public class Bomb{
public Bomb(final Player player){
new Thread(() -> {
try {
Thread.sleep(1500);
Platform.runLater(() -> player.refresh());
} catch (InterruptedException e) {}
}
}).start();
}
}
Of the different approaches, I recommend the PauseTransition over the others as then you don't need to deal with concurrency details such as threading, which are easy to get wrong.
Your run method calls [this.]notify() without being synchronized on this. I would expect it to always throw an IllegalMonitorStateException.
Also, it's almost always a mistake to call notify() without also setting some variable that other threads can examine. The problem with notify() is that it does not do anything at all unless some other thread happens to be in a wait() call for the same object. Without proper synchronization, you have no way to guarantee that that will be true.
There's only one right way to use wait() and notify(), and that's in a design pattern that Oracle calls a guarded block. https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.
i have just attempted to add something to my game where if one player is hit by a bullet his health goes down. problem is when i am checking for this, CPU is at 100% and everything sooo laggy. This is a problem. here is the thread i am using:
package Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
public class BulletCollision implements Runnable {
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public Thread checkBulletCollision = new Thread(this);
public void checkPlayerBulletCollide() {
if (player2.getBulletX() > player1.getX() &&
player2.getBulletX() < player1.getX() - 50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(
Level.SEVERE, null, ex);
}
}
}
}
i am pretty sure this is where the problem is. there are no errors when compiled or ran. if anyone could help that would be amazing! and i just make this class so the code is not perfect. i have tried a lot to fix this, the Threads start() method is being called in my Display class which only displays the JFrame. i previously had the start method in one of my player classed.
The problem is not in this code. There are one or two flaws, but nothing in this code that would result in laggyness ... as far as I can tell.
FWIW, the flaws are as follows:
1) This is bad style:
checkBulletCollision.sleep(100);
The Thread.sleep method is static, so you should invoke it as:
Thread.sleep(100);
2) Your thread run() method should return if it receives an interrupt. You have coded it to keep going ... which would defeat the purpose of interrupting it.
In my opinion, using this block free running in a separate thread is not correct in this case.
while(true) {
checkPlayerBulletCollide();
try {
checkBulletCollision.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
}
}
I'd only do this once each frame, I'd call the checkPlayerBulletCollide() from the drawing logic.
Also note that Thread.sleep() is a static function, so you can't make a specific Thread instance sleep from another Thread, a Threac can just put itself to sleep...
EDIT If you would like to code nice and clean (which is very good), I'd advise using the locking mechanisms we have from Java 1.5 on.
Even though this is (in the current context of 2 users with 1 bullet each) not lightweight ebough, I'd use a BlockingQueue. The checking thread would have to issue a queue.take(), but the actual Integer value wouldn't matter (later on e.g. with more bullets or players, you could put objects in the queue that specify which bullets and which users to check...). The drawing logic - or the logic controlling the drawing would do queue.offer(0). The checking Thread would look like this:
public class BulletCollision implements Runnable{
Player1 player1 = new Player1();
Player2 player2 = new Player2();
public BlockingQueue<Integer> checkQueue = new LinkedBlockingQueue<Integer>();
public void checkPlayerBulletCollide() {
if(player2.getBulletX() > player1.getX() && player2.getBulletX() < player1.getX() -50) {
player2.decHealth(50);
}
}
#Override
public void run() {
while(true) {
try {
queue.take();
checkPlayerBulletCollide();
} catch (InterruptedException ex) {
Logger.getLogger(BulletCollision.class.getName()).log(Level.SEVERE, null, ex);
break; //I'd put this here. If we were interrupted, the hread should stop gracefully.
}
}
}
}
Also, when you're done with drawing a frame, you should issue a queue.offer(0);