Several threads for run render in Android 3D game. Thread-safe? - java

For a long time I tried to make smooth animation for the application. And I got this solution: several threads launch draw frame of SceneRenderer:
public class OGLView extends GLSurfaceView {
public void init(Context context, int versionGLES) {
...
renderer = new SceneRenderer(context, versionGLES);
setRenderer(renderer);
...
}
}
public class SurfaceRunnable implements Runnable {
...
#Override
public void run() {
while(true) {
surfaceView.requestRender(); // draw frame
if (Thread.currentThread().isInterrupted()) break;
}
}
}
public class SurfaceExecutor implements Executor {
private List<Thread> threads = new ArrayList<>();
#Override
public void execute(#NonNull Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setPriority(10);
thread.start();
threads.add(thread);
}
...
}
public class GameActivity extends AppCompatActivity {
private SurfaceExecutor executor = new SurfaceExecutor();
#Override
protected void onResume() {
...
SurfaceRunnable sr = new SurfaceRunnable(oglView);
/* run four threads for SceneRender */
executor.execute(sr);
executor.execute(sr);
executor.execute(sr);
executor.execute(sr);
...
}
}
As a result, the animation has become smoother. Long testing of the application did not lead to errors. Testing on different device configurations did not detect changes in the animation rate. Question: How much is this approach thread safe? All drawing and operations with matrices are done in SceneRenderer. Thank you all. Please, excuse my English.

Without a complete application it's impossible to say whether this is safe or not, as that entirely depends on what those 4 threads are doing and what resources are shared across them.
In all honesty though, this looks like a nasty hack. All 4 threads seem to be doing the same thing, any any fix of "just run 4 copies of the same thing and hope" seems to be running better by luck rather than any particular intentional design benefit.

Related

What is the cleanest way to create, start, and manage long-running threads?

Threads add a lot of verbal to the code and make it harder to understand and reason about. Look at this code for example:
public class ConnectionListener implements Runnable {
private Thread thread;
private boolean running;
public void start() {
if (!running) {
thread = new Thread(this);
thread.start();
}
}
public void stop() {
if (running) {
running = false;
thread.interrupt();
}
}
#Override
public void run() {
running = true;
while (running) {
// Do some crap
}
}
}
The whole concern of this class should be listening for connection requests from the network. But look how many lines of code are added just for managing a thread. Is there any way to make this code cleaner?! I don't want to see the thread = new Thread();, not the thread variable and not any of the stop()/start() methods!
Of course I know what the ExecutorService is... But what if I want to manage a long-running thread? By long-running thread, I mean a thread with a life cycle long as the application's life cycle.
Do you have any good solution for me? A way to remove the thread creation and management concerns from a class without making the class extend another class?
I solved the problem by using a single-threaded executor service. I've also read about the performance differences between Plain Thread, ThreadPool and SingleThreadExecutor - SingleThreadExecutor VS plain thread.
Using a single thread executor allows me to start a single thread and manage it using its Future. See code example:
public void func(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
Future<?> f = es.submit(Some Runnable);
}
Thanks to #BasilBourque that gave me this solution in the comments.

can't get sequential behavior Java Swing [duplicate]

basically, I have this code which was initially working with console i/o now I have to connect it to UI. It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.
I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.
This is the button on GUI class containing the method that needs to change this GUI.
public class GUI {
...
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.startTest(index, idUser);
}
});
}
This is the method startTest from another class which contains instance of Question class.
public int startTest() {
for (int i = 0; i < this.numberofQuestions; i++) {
Question qt = this.q[i];
qt.askQuestion(); <--- This needs to change Label in GUI
if(!qt.userAnswer()) <--- This needs to get string from TextField
decreaseScore(1);
}
return actScore();
}
askQuestion method:
public void askQuestion() {
System.out.println(getQuestion());
/* I've tried to change staticaly declared frame in GUI from there */
}
userAnswer method:
public boolean userAnswer() {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
if( Objects.equals(getAnswer(),userInput) ) {
System.out.println("Correct");
return true;
}
System.out.println("False");
return false;
}
Thanks for help.
You're correct in thinking that it related to threads.
When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.
As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.
A good way to implement it would be this:
public class TestWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
//This is where you execute the long running
//code
controller.startTest(index, idUser);
publish("Finish");
}
#Override
protected void process(List<String> chunks) {
//Called when the task has finished executing.
//This is where you can update your GUI when
//the task is complete or when you want to
//notify the user of a change.
}
}
Use TestWorker.execute() to start the worker.
This website provides a good example on how to use
the SwingWorker class.
As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:
Thread t = new Thread(){
#Override
public void run(){
// do stuff
}
};
t.start();
Or if you use Java 8+:
Thread t = new Thread(() -> {
// do stuff
});
t.start();

How to safely stop a thread launched from an alertdialog?

When I show an alertdialog, I start a thread that starts a 30 second countdown to update a determinate progressbar shown in this alertdialog.
I create the runnable as a static inner class so that I don't leak the context(activity), but then of course I can't access the flag to stop the thread, nor the views I want to update. How can I get around this?
public class MyDialogFragment implements DialogInterface.onShowListener, DialogInterface.onDismissListener {
private boolean stopThread = false;
private Progressbar countdownBar;
private TextView countdownRatio;
#Override public void onShow() {
Thread progressThread = new Thread(new myRunnable());
progressThread.start();
}
#Override public void onDismiss() {
stopThread = true;
this.dismiss();
}
private static class myRunnable implements Runnable {
int progressStatus = 0;
int numSeconds = 30;
#Override public void run() {
while (!threadStop && progressStatus < numSeconds) {
progressStatus++;
handler.post(new Runnable() {
public void run() {
countdownBar.setProgress(progressStatus);
countdownRatio.setText(progressStatus + "/" + numSeconds + " secs");
}
});
try {
// update the counter every sec
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
First - don't use Thread - you're asking for troubles, especially that you don't seem to be comfortable with multi-threaded programming. It's a tricky topic with tons of pitfalls. It's definitely not for noobs.
You may use AsyncTask for this - it has nice integration with UI event loop via AsyncTask.onProgressUpdate(). AsyncTask uses internal thread pool.
http://developer.android.com/guide/components/processes-and-threads.html#Threads
AsyncTask is ok for most trivial stuff. For more advanced uses try using Service with worker threads and message bus to communicate with fragments or activities. There is plenty of libraries for asynchronous programming. I can recommend this one:
https://github.com/stephanenicolas/robospice
It's main purpose if networking, but you can use it for other stuff as well.
Third solution is Loader API:
http://developer.android.com/reference/android/content/Loader.html
It's intended for asynchronous loading of data from database (SQLite is slow), but it's quite easy to use it for other stuff, such as data processing.
Remember: if you use Thread, there are 2 possibilities:
You are expert and you know what you're doing
You are green and you're doing it wrong

libgdx - doing something in other thread not working

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.

Sharing object and controlling thread execution from main thread

I am trying to solve quite easy problem. I have a main thread, which draws a frame and another thread(FrameThread) that prepares this frame every time. Both threads should share same MyFrame object. I want to control FrameThread from the main thread, i.e.: MyFrame is ready -> draw it in main thread -> keep FrameThread running. Currently i did following:
private class FrameEngine
{
private boolean isFrameReady = false;
private MyFrame frame;
public synchronized void generateFrame()
{
while(isFrameReady)
wait();
frame = FrameGenerator.nextFrame();
isFrameReady = true;
notifyAll();
}
public synchronized MyFrame getFrame()
{
while(!isFrameReady)
wait();
isFrameReady = false;
notifyAll();
return frame;
}
}
After that i create FrameThread:
private class FrameThread implements Runnable
{
private final FrameEngine frame_eng;
public FrameThread( FrameEngine engine )
{
frame_eng = engine;
}
#Override
public void run()
{
while(true)
frame_eng.generateFrame();
}
}
And finally main thread:
FrameEngine frame_engine = new FrameEngine();
Thread frameThread = new Thread( new FrameThread( frame_engine ) );
frameThread.start();
...
while(true)
{
...
drawFrame( frame_engine.getFrame() );
...
}
So my goal is: FrameThread executes in background and stops right after frame is ready. I am very novice in Java, and i feel there is much better and safer way to achieve it. Could you give me an advice about it? Thank you.
This is the classic producer-consumer problem. I suggest that you avoid using wait() and notify() because they are difficult to get right, even for seasoned developers.
Instead, check out the BlockingQueue interface and use the example in the comments as a guide. This seems to be exactly what you're looking for.
If it is required that no more than one frame is generated in advance, then use an ArrayBlockingQueue with a capacity of 1.
I should also mention that in both your example and the BlockingQueue example in the link above, semantics for shutting down the producer and consumer threads are not explained. You will need to add a stopping mechanism to be complete, otherwise your program will not shut down on its own, even after the main thread has died.

Categories