libgdx - doing something in other thread not working - java

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.

Related

Safely pausing and resuming a thread

I want to create a thread to make some HTTP requests every few seconds and is easy to pause and resume at a moments notice.
Is the way below preferred, safe and efficient?
public class Facebook extends Thread {
public boolean running = false;
public void startThread() {
running = true;
}
public void stopThread() {
running = false;
}
public void run() {
while(true) {
while(running) {
//HTTP Calls
Facebook.sleep(2000);
}
}
}
}
Your Code:
In your example, the boolean should be volatile boolean to operate properly. The other issue is if running == false your thread just burns CPU in a tight loop, and you probably would want to use object monitors or a Condition to actually wait idly for the flag to become true again.
Timer Option:
I would suggest simply creating a Timer for this. Each Timer implicitly gets its own thread, which is what you are trying to accomplish.
Then create a TimerTask (FacebookTask below is this) that performs your task and from your main control class, no explicit threads necessary, something like:
Timer t;
void resumeRequests () {
if (t == null) { // otherwise its already running
t = new Timer();
t.scheduleAtFixedRate(new FacebookTask(), 0, 2000);
}
}
void pauseRequests () {
if (t != null) { // otherwise its not running
t.cancel();
t = null;
}
}
Note that above, resumeRequests() will cause a request to happen immediately upon resume (as specified by the 0 delay parameter); you could theoretically increase the request rate if you paused and resumed repeatedly in less than 2000ms. This doesn't seem like it will be an issue to you; but an alternative implementation is to keep the timer running constantly, and have a volatile bool flag in the FacebookTask that you can set to enable/disable it (so if it's e.g. false it doesn't make the request, but continues checking every 2000ms). Pick whichever makes the most sense for you.
Other Options:
You could also use a scheduled executor service as fge mentions in comments. It has more features than a timer and is equally easy to use; they'll also scale well if you need to add more tasks in the future.
In any case there's no real reason to bother with Threads directly here; there are plenty of great tools in the JDK for this job.
The suggestion to using a Timer would work better. If you want to do the threading manually, though, then something more like this would be safer and better:
class Facebook implements Runnable {
private final Object monitor = new Object();
public boolean running = false;
public void startThread() {
synchronized (monitor) {
running = true;
monitor.notifyAll();
}
}
public void stopThread() {
synchronized (monitor) {
running = false;
}
}
#Override
public void run() {
while(true) {
try {
synchronized (monitor) {
// Wait until somebody calls startThread()
while (!running) {
monitor.wait();
}
}
//HTTP Calls
Thread.sleep(2000);
} catch (InterruptedException ie) {
break;
}
}
}
}
Note in particular:
You should generally implement Runnable instead of subclassing Thread, then use that Runnable to specify the work for a generic Thread. The work a thread performs is not the same thing as the thread itself, so this yields a better model. It's also more flexible if you want to be able to perform the same work by other means (e.g. a Timer).
You need to use some form of synchronization whenever you want two threads to exchange data (such as the state of the running instance variable). There are classes, AtomicBoolean for example, that have such synchronization built in, but sometimes there are advantages to synchronizing manually.
In the particular case that you want one thread to stop work until another thread instructs it to continue, you generally want to use Object.wait() and a corresponding Object.notify() or Object.notifyAll(), as demonstrated above. The waiting thread consumes zero CPU until it is signaled. Since you need to use manual synchronization with wait/notify anyway, there would be no additional advantage to be gained by using an AtomicBoolean.
Edited to add:
Since apparently there is some confusion about how to use this (or the original version, I guess), here's an example:
class MyClass {
static void main(String[] args) {
FaceBook fb = new FaceBook();
Thread fbThread = new Thread(fb);
fbThread.start();
/* ... do stuff ... */
// Pause the FaceBook thread:
fb.stopThread();
/* ... do more stuff ... */
// Resume the FaceBook thread:
fb.startThread();
// etc.
// When done:
fbThread.interrupt(); // else the program never exits
}
}
I Would recommend you to use a guarded blocks and attach the thread to a timer

JFrame freezes while running the code continuously

I have problem while working with JFrame, which get freezes while
running the code continuously. Below is my code:
On clicking on btnRun, I called the function MainLoop():
ActionListener btnRun_Click = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
MainLoop();
}
};
Implementation of MainLoop():
void MainLoop()
{
Hopper = new CHopper(this);
System.out.println(Hopper);
btnRun.setEnabled(false);
textBox1.setText("");
Hopper.getM_cmd().ComPort = helpers.Global.ComPort;
Hopper.getM_cmd().SSPAddress = helpers.Global.SSPAddress;
Hopper.getM_cmd().Timeout = 2000;
Hopper.getM_cmd().RetryLevel = 3;
System.out.println("In MainLoop: " + Hopper);
// First connect to the validator
if (ConnectToValidator(10, 3))
{
btnHalt.setEnabled(true);
Running = true;
textBox1.append("\r\nPoll Loop\r\n"
+ "*********************************\r\n");
}
// This loop won't run until the validator is connected
while (Running)
{
// poll the validator
if (!Hopper.DoPoll(textBox1))
{
// If the poll fails, try to reconnect
textBox1.append("Attempting to reconnect...\r\n");
if (!ConnectToValidator(10, 3))
{
// If it fails after 5 attempts, exit the loop
Running = false;
}
}
// tick the timer
// timer1.start();
// update form
UpdateUI();
// setup dynamic elements of win form once
if (!bFormSetup)
{
SetupFormLayout();
bFormSetup = true;
}
}
//close com port
Hopper.getM_eSSP().CloseComPort();
btnRun.setEnabled(true);
btnHalt.setEnabled(false);
}
In the MainLoop() function, the while loop is running continuesly until the Running is true problem is that if i want to stop that while loop i have to set Running to false which is done at another button btnHalt:
ActionListener btnHalt_Click = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textBox1.append("Poll loop stopped\r\n");
System.out.println("Hoper Stopped");
Running = false;
}
};
but btnHalt is not responding, whole frame is get freeze, also not
showing any log in the textarea.
Swing is a single thread framework. That is, there is a single thread responsible for dispatching all the events to all the components, including repaint requests.
Any action which stops/blocks this thread will cause your UI to "hang".
The first rule of Swing, NEVER run any blocking or time consuming tasks on the Event Dispatching Thread, instead, you should use a background thread.
This runs you smack into the second rule of Swing. Never create, modify or interact with any UI component outside of the EDT.
There are a number of ways you can fix this. You could use SwingUtilities.invokeLater or a SwingWorker.
SwingWorker is generally easier, as it provides a number of simple to use methods that automatically re-sync there calls to the EDT.
Take a read through Concurrency in Swing
Updated
Just so you understand ;)
Your MainLoop method should not be executed within the context of the EDT, this is very bad.
Also, you should not be interacting with any UI component from any thread other the then the EDT.

Synchronized with GLThread in Android

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

How can I schedule a background thread to play sounds in my app?

I have a process which should react on some events. So when playFromList() is called it plays some sound from soundpool. Then in a thread I set a flag and for 3,5 seconds it should not play any sounds.
What I got is: It plays sound and if than wait 3,5 seconds. If playFromList() is called 5 times in 3,5 seconds it still gets to SoundManager.playSound(listNr), and still is done in 17,5 seconds. And its not exactly what I wanted. I wanted method SoundManager.playSound(listNr) called only once.
public class Settings{
public static boolean flag = false;
}
public class Main{
public void playFromList(int listNr,int g){
if(!Settings.flag){
SoundManager.playSound(listNr);
if(g ==0){
mpVolume((float) 0.3);
t5sec.run();
}else{pauseMus();}
}
}
private Handler vijfSeconden = new Handler(){
public void handleMessage(Message msg){
mpVolume((float)0.8);
}
};
Thread t5sec = new Thread(){
public void run(){
if(Settings.flag == false){
Settings.flag = true;
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
Settings.flag = false;
e.printStackTrace();
}
vijfSeconden.sendEmptyMessage(0);
Settings.flag = false;
}
}
};
}
There are few problems with the code. Probably most important thing that is strange is
t5sec.run(), in Java you you should use start method on the Thread object to start new Thread. As written it will execute in the calling thread.
Second problem is absolute lack of synchronization, one way to fix that, I guess, would be to use AtomicBoolean instead of boolean in Settings.flag
Another issue is that it is quite expensive to start new thread every time. It is a bit hard to tell from the description precisely what you want to do, but if my understanding is correct you should just do something like this:
if ( (System.currentTimeInMillis() - lastTimePlayed) < 3500) {
playSound();
lastTimePlayed = System.currentTimeInMillis();
}
that's it and no threads required. You might want to use AtomicInteger to hold lastTimePlayed value if you want your class to be thread safe.

Java Swing Threading with Updatable JProgressBar

First off I've been working with Java's Concurrency package quite a bit lately but I have found an issue that I am stuck on. I want to have and Application and the Application can have a SplashScreen with a status bar and the loading of other data. So I decided to use SwingUtilities.invokeAndWait( call the splash component here ). The SplashScreen then appears with a JProgressBar and runs a group of threads. But I can't seem to get a good handle on things. I've looked over SwingWorker and tried using it for this purpose but the thread just returns. Here is a bit of pseudo code. and the points I'm trying to achieve.
Have an Application that has a SplashScreen that pauses while loading info
Be able to run multiple threads under the SplashScreen
Have the progress bar of the SplashScreen Update-able yet not exit until all threads are done.
Launching splash screen
try {
SwingUtilities.invokeAndWait( SplashScreen );
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }
Splash screen construction
SplashScreen extends JFrame implements Runnable{
public void run() {
//run threads
//while updating status bar
}
}
I have tried many things including SwingWorkers, Threads using CountDownLatch's, and others. The CountDownLatch's actually worked in the manner I wanted to do the processing but I was unable to update the GUI. When using the SwingWorkers either the invokeAndWait was basically nullified (which is their purpose) or it wouldn't update the GUI still even when using a PropertyChangedListener. If someone else has a couple ideas it would be great to hear them. Thanks in advance.
I actually got ready to post better code to help out and found my solution. I thank you for all who helped.
For running a series of operations in the background and reporting progress, use SwingWorker.
The background method does the background processing.
Use the publish method to post periodic status updates.
Override the process method to handle the updates (process always executes on the EDT).
progressBar = new JProgressBar();
sw = new SwingWorker<Boolean,Integer>() {
protected Boolean doInBackground() throws Exception {
// If any of the operations fail, return false to notify done()
// Do thing 1
publish(25); // 25% done
// Do thing 2
publish(50); // 50% done
// Do thing 3
publish(75); // 75% done
// Do thing 4
return true;
}
protected void process(List<Integer> chunks) {
for (Integer i : chunks)
progressBar.setValue(i);
}
protected void done() {
try {
boolean b = get();
if (b)
progressBar.setValue(100); // 100% done
else
// Notify the user processing failed
}
catch (InterruptedException ex) {
// Notify the user processing was interrupted
}
catch (ExecutionException ex) {
// Notify the user processing raised an exception
}
}
};
Addendum:
This can be extended to multiple tasks, it just requires changing how you approach setting the progress bar. Here's what comes to mind:
Have an array of completion counter, one per task.
int[] completions = new int[numTasks];
Arrays.fill(completions,0);
Start the SwingWorkers, each passed an index number. The process or done methods then call something like this to update the overall progress bar.
void update(int index, int percComplete) {
completions[index] = percComplete;
int total = 0;
for(int comp: completions)
total += comp/numTasks;
overallPB.setValue(total);
}
Optionally, display a JProgressBar per task.
Addendum 2:
If the tasks vary in completion time (eg, cache hit vs cache miss), you may want to investigate ProgressMonitor. It's a progress dialog that only appears if the task takes more than some (configurable, default 500ms) amount of time.
No need to call the frame inside invokeAndWait but you should update progress bar state like this.
try {
SwingUtilities.invokeAndWait( new Runnable() {
public void run() {
//update state of the progress bar here
}
});
} catch (InterruptedException e) {
} catch (InvocationTargetException e) { }

Categories