I am trying to call GLFW.glfwPollEvents() in an asynchronous task that runs every tick (1/30th of a second in this case). This ticking timer effectively controls when every action in the app takes place.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
#Override
public void run(){
//... more code ...
GLFW.glfwPollEvents();
//... more code ...
}
}, 33, 33);
But, this does not work because
This function may only be called from the main thread.
(from the documentation)
How can I call this on the main thread? When it isn't run on the main thread, the application crashes. I'm looking for something like
GLFW.dispatchMainThread(new GLFWRunnable(){
public void run(){
//...
}
});
This is possible to do in swing and awt by using
EventQueue.invokeLater(new Runnable(){
public void run(){
//...
}
});
But the same code doesn't work for GLFW.
How can I run a task on GLFW's main thread using LWJGL without using a while(true) loop on the main thread?
Since GLFW's main thread must be the same as the application's main thread (a limitation in GLFW; that's where it puts the OS message queue that is handled differently by swing/awt it seems - see my answer here) I would do things the other way around.
My main thread would have the forever loop (probably using glfwWaitEvents so as not to eat CPU time needlessly). I would then post any events that were app-specific to another thread that does the processing. Your message processing is now decoupled from your message receiving.
This way I don't have to wait for 1/30th of a second to get OS messages (it always frustrates me when an app lags opening a menu, registering a click, or arrowing through a list).
Your update thread can even sleep for 1/30th of a second (or less, sleeping again if not enough time has passed or not if a second high-priority queue needs work) and only wake up to check for queued events as an extremely simple scheduling method.
The answer I linked to above has a link to an LWJGL Multithreaded Demo that does something very similar. Their renderLoop would be your updateLoop and would draw from a queue and do processing before going to sleep again instead of updating and presenting graphics.
Related
I have three questions which are closely related in that they are born out of each other and represent a train of thought, so I am posting them under one question. It would not help me construct the big picture of my question if I posted them separately.
1) Could you please explain in simple language what SwingUtilities.invokeLater does? I understand threading, dare I say quite a bit, but still the language of the documentation confuses me. It says:
Causes doRun.run() to be executed asynchronously on the
AWT event dispatching thread. This will happen after all
pending AWT events have been processed. This method should
be used when an application thread needs to update the GUI.
In the following example the invokeLater call queues
the Runnable object doHelloWorld
on the event dispatching thread and
then prints a message.
If I put some effort in to make sense of what that says, I think here is what it says, but I couldn't be so sure about it. I think it says:
The invokeLater method schedules the main window creation and the setting up of its dispatcher / message pump on the primary thread of the application only and not on a separate thread. It does it by posting the message to create the window and set it up on the main / primary application thread. In other words, the main thread is saying to us, "The window you are asking me to create will be created after I am done doing everything else that is on my plate right now."
But then two things confuses me, which I list as the two questions below.
2) Then why do I need to implement the new window's message loop as a Runnable. This implies that I want a separate thread to execute that message loop.
3) I printed out the current thread Id's in the function that creates the window and the function that is the window's message loop, and they are both different threads. So, each window in Swing runs on its own thread? That is insane. Can you please explain to me what is happening here? And also if you could please explain in a paragraph or two the threading model of GUI applications created in Swing?
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainWindowEventLoop());
System.out.println(String.format("Main thread %1$d started.",
Thread.currentThread().getId()));
}
public class MainWindowEventLoop implements Runnable {
#Override
public void run() {
JFrame mainWindow = new MainWindow("Main Window");
System.out.println(String.format("Main window loop running on thread %1$d.",
Thread.currentThread().getId()));
}
}
Output:
Main thread 1 started.
Main window loop running on thread 14.
It's a little complicated, but Swing is not thread safe. To run the GUI asynchronously and safely, Sun/Oracle uses a locking pattern called Ad-Hoc Thread Confinement. All Swing components must run on the AWT EDT (Event Dispatch Thread) or the result is not thread safe.
Here's a link to Oracle's tutorial. Try to read all of those sections, see if it makes more sense.
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/
Each window does NOT run on its own separate thread. There is only one EDT. Each windows runs on the SAME thread, the EDT. Each Runnable you send to the EDT is executed sequentially, one after the other, when the EDT has the opportunity to do so. Hence the "later" part of invokeLater().
Basically all the swing windows are bounded to main thread. Every single component in swing runs as thread. After the completion of an event control again returns back to main thread which waits for an event to occur.
I've got a Handler that runs a runnable task every 2 seconds. It runs a fairly intensive task (executes a shell command). Every time the I run handler.postDelayed(update, 2000); the user interface lags (for 2 seconds). How do I stop this lag?
I know there's lag because I have a dynamic interface, so I can move around a view and when the handler is run the interface becomes unresponsive for the 2 seconds.
Is there a way to go around this?
You are doing this work on the main UI thread, which is not acceptable for your user to have a good experience, as you have already identified.
You can instead create a new background thread for your handler to run any posted runnables on, which will take the least amount of code change:
mHandlerThread = new HandlerThread("YourHandlerThread");
mHandlerThread.start();
handler = new Handler(mHandlerThread.getLooper());
// Now post your runnable, as before
handler.postDelayed(update, 2000);
Just keep in mind that you cannot touch any UI elements from this thread, as that is not allowed by Android.
when the handler is run the interface becomes unresponsive for the 2 seconds
That means that you are doing two seconds' worth of work on the main application thread. Doing 2 milliseconds' worth of work is more appropriate.
The Runnable that is passed to postDelayed() has its run() method called on the main application thread. If this work will take more than a millisecond or two, you should be using something other than Handler and postDelayed() for your every-two-seconds work, such as a ScheduledExecutorService.
Handler is a way to run code on the UI Thread in Android.
If you don't need your code run on the UI Thread, you may want to consider just making your own Thread or using an Executor.
I've fixed it. Thanks to everyone notifying me that the Handler runs on the UI thread...
I've now run a separate thread to update the variable used in the handler task:
double p = 0;
public void z(){
Thread t = new Thread(){
#Override
public void run(){
p = a.b();
}
};
t.start();
}
Runnable y = new Runnable() {
#Override
public void run() {
z();
c.setText(String.valueOf(p));
d.setProgress(Float.valueOf(String.valueOf(p / 100)));
handler.postDelayed(this, 2000);
}
};`
This is weird: When I start a schedule using timer.scheduleAtFixedRate, it takes a long time and then throws a OutOfMemoryError: Java heap space, but if I just called the timerTask.run() method in the main thread, it works just fine.
The method I called is not open-source, so I cannot just paste it out. But could anyone help me analyse some possibilities on this scenario. What is the difference between running it in a timerTask thread and running it in the main thread?
Thanks a lot!
The code snippet is just as simple as follows:
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
AModule.load(tmpFilePath); //not open-source
}
}
timer.scheduleAtFixedRate(task, new Date(), 1*60*1000); //OOME
//If I change the upper code to:
task.run() //it just works fine
The AWT timer runs in its own thread. If by "main thread" you mean the UI thread, or event queue, then:
Perhaps your closed source code is accessing Swing some how. Swing components should only be accessed from the event thread. You might have trouble when running in the timer yet always run fine in your main thread.
If that's the case you're lucky. Calling Swing from another thread usually works. I never have problems till I'm demoing or the client tries to use it. And the problems are often not repeatable.
I have read that the main UI thread in android should not call sleep.
However, my application needs to :
call thread1 from main UI thread
call thread2 from main UI thread.
Use the output (2 images) of the 2 thread, add them and then display them.
I am using Thread.sleep() so that the main thread waits thread1 and thread2 till they are done. However mImageview.setbitmap is not working after i call it in the main thread (after sleep).
can u pls advise me how i should do this?
Multithreading in Android should be done Asynchronously. For this purpose, you should use the AsyncTask-class.
For your case, you would for example create a taks to load (or process) those two images. While the process is running (in another thread, off the UI-thread), you could show a ProgressBar that shows to the user that your application is currently busy (this is then done on the UI-thread).
When the task has finished, you get the results (your two images) from the task, hide the progress-bar and show everything to the user.
Despite the fact that a non-reacting GUI always has the feeling that your application frooze, if a UI-Thread is blocked for more then 5 seconds (which is a looong time), your application will be Force-closed as it is not "reacting" (and an ANR will be raised).
It's not just Thread.Sleep(). In the GUI thread, do whatever you need to to start the two threads/tasks/whatever and then exit the event handler.
Do not wait in GUI event-handlers! Not in Java, C++, C, Delphi, anything. Use an async task, or a Handler, and signal to the GUI thread. Thread 1 signals that it is done, thread 2 signals that it is done. In either case check to see if the data has been returned by the other thread. If it has, you have both sets of returned data and so you can add them and display them.
Do not wait in GUI event-handlers.
You can simply use Threads And Handlers for this purpose.
Here is a small demo for this,
Create a Handler in your onCreate like this,
Drawable d=null;
Handler handler=new Handler()
{
public void handleMesaage(Message msg)
{
if(msg.what==0)
{
imageView.setBackgroundDrawable(d);
}
}
};
And now call Your Thread like this,
Thread t=new Thread(new Runnable()
{
#Override
public void run() {
InputStream is = (InputStream) new URL(url).getContent();
d = Drawable.createFromStream(is, "src name");
handler.sendEmptyMessage(0);
}
});t.start();
I would suggest to use the ExecutorService. Here is how
Create the two image loading activities as Runnable tasks.
Execute them with the ExecutorService.
Use ExecutorService.awaitTermination(); for the main thread to wait for Runnable tasks to complete. Its documentation reads
Blocks until all tasks have completed execution after a shutdown
request, or the timeout occurs, or the current thread is interrupted,
whichever happens first.
This is the Asynch way of doing it and I guess should be preferred.
I have a little app that at the moment consists of a JPanel with an "Open File" button.
Once the user clicks the button a new JFileChooser is created so the user can select a file.
Once the user selected a file, this file will be processed.
What I want to do, is to set the text on the JPanel to "Processing File" While the file is being processed.
I have all the code for this and then after the code, I call the method to actually process the file, but what happens is that it processes the file first and then update the gui components
How do I get around this?
You should process your task in another thread rather than in Event Dispatch Thread (EDT).
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Processing File");
new Thread(new Runnable() {
public void run() {
// do something long task
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusLabel.setText("Done!");
}
});
}
}).start();
}
Using a Swing Worker Thread
As you've identified, processing the file means the Swing thread (which invoked this) is waiting for the processing to complete. So you need to invoke this in a separate thread.
The processing should run in parallel with other stuff (including the GUI updates). Once it's complete, it can call back on another component to signal that the GUI can update a status message (See SwingUtilities.invokeLater() and create an appropriate Runnable to do this)
You should process the file in a separate thread. This will allow you to kill two birds with one stone: First, your app will be more responsive. Second, the title change will actually happen.
OTOH, dealing with multithreading is a bit tricky. In particular, you may want to block some operations while the processing thread is running and then you need to rollback upon completion.
Keep in mind that the new thread cannot do GUI operaions directly: The non-GUI thread must use SwingUtilities.invokeLater() to ask the GUI thread to carry out operations on its behalf.