Skip to main content

Questions about threading, EDT, Foxtrot, etc - coming from lcdui mentality.

11 replies [Last post]
nafs
Offline
Joined: 2008-06-10
Points: 0

Hello,

As I write this, I have several tabs (including Shai's blog) open trying to fully comprehend the various intricacies. I have some questions, hopefully they will also benefit those who are in the same boat as me.
Note that the code snippets below are fabricated such for explanation's sake.

1) Here is what I know about the EDT... the EDT is this one big massive thread which probably has a internal Queue. All kinds of UI activities (drawing, paint, flush, god knows what else) are queued and subsequently executed in the EDT. Based on my limited Swing experience, I also know that no "heavy" tasks should be executed in this thread. Fine, makes sense.

2)
While working on LCDUI, here's a simple snippet of my code:
public void commandAction()
{
connectToServerAndGetFile();
}
This will not work. If I run this code, my UI will hang because, according to MIDP docs, "the commandAction should return immediately". Again, this makes sense to me. Therefore I fix the issue with an asynchronous call instead:
public void commandAction()
{
new Thread(new Runnable(){ void run(){connectToServerAndGetFile();}}).start();
}
Works like a charm.

Ok now here is the part that confuses me. While using LWTUI, I have something like this:
public void actionPerformed()
{
connectToServerAndGetFile();
}
The above code works fine... why? I dont understand. My theory is that in the case of lcdui, there is no concept of EDT and hence all my tasks are happening in 1 big thread. Which is why I was required to call connectToServerAndGetFile() asynchronously (in that anon class code). But I dont exactly know what happens different in LWTUI.

2)
In regards to the above point, which of th following "styles" is considered better practice:
public void actionPerformed()
{
connectToServerAndGetFile();
}
OR
public void actionPerformed()
{
new Thread(new Runnable(){connectToServerAndGetFile();}}).start();
}
Both of the above code snippets work, but what is the recommended way to do this? Or am I just overthinking the problem..

3)
Let us look at the docs for callSerially()...
"Causes the runnable to be invoked on the event dispatch thread.".
What exactly does it mean to "invoke something on the EDT"? Why would i want to do it? I am looking for scenarios where this is used.

4)
I dont understand what is the difference between callSerially() and callSeriallyAndWait()... the docs state, "..with the added benefit of waiting for the method to be invoked". First of all, which method are they talking about here? The run() method of the Runnable? Again... would appreciate if someone could give me a practical scenario which demonstrates the use of these.

5)
Ok now I will try to connect two dots of my understanding...
In one of my earlier points (#2), I demonstrated how connectToServerAndGetFile() worked inside actionPerformed() whether invoked asynchronously or synchronously. The reason for this is because actionPerformed() is not invoked on the EDT. Ok good.
So... then WHY does the following code fail:
public void actionPerformed()
{
Display.getInstance().callSerially( new Runnable(){connectToServerAndGetFile()}));
}
I get an IllegalException saying, "callSerially() must never be invoked inside the EDT"..... BUT HEY!.. wait a sec, didn't I just establish earlier that actionPerformed() doesnt operate on the EDT!?
Please help me understand this.

Thanks all..

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jack_jia
Offline
Joined: 2006-01-29
Points: 0

I think defensive programming should be used here. The EDT should make a new callserially-queue and process the previous one, and then there will be no problem to invoke callserially within EDT thread.

public synchronized void processQueue() {
Vector queue = mCallseriallyQueue;
mCallseriallyQueue = new Vector();
process(queue);
}

vprise
Offline
Joined: 2003-11-07
Points: 0

The current version of lwuit doesn't throw that exception

nafs
Offline
Joined: 2008-06-10
Points: 0

Hi again,

1)
With reference to callSerially(), you said: [i]"Say you opened your thread and downloaded data, then you want to update the UI on the screen. If you do it from a separate thread things break in "creative" ways so you would like your code to continue running from the EDT thread (after the other thread completes) in order to update the UI"[/i]

First of all, when you say ".. do it from a separate thread", you are referring to the same thread in which I downloaded the data?
Anyway, I understand your explanation but I am having a hard time coming up with practical scenarios that use it, especially since callSerially() cannot be invoked within the EDT (ie, actionPerformed()).
However, I came up with a scenario.. I think.. tell me if I got this right:
Let's say you want to create a very simple application that displays all the PDF files in the phone. So essentially, this means the following sequential steps:
CASE 1:
1 - applications starts
2 - begin scanning file system
3 - upon encountering a PDF file, add it's name to the Form as a Label
4 - scanning finished. Display the form.

Done. But.. the problem with this app is that the form isnt displayed till the whole scanning process. Suppose you want the form to displayed as soon as the app starts, while the scanning happens in th background. That is,
CASE 2:
1 - application starts
2 - begin scanning file system [b]asynchronously [/b]
2 - Display the form.
3 - When the scanning thread encounters a PDF file, it adds the filename to the Form as a Label.

Are you saying that while doing step #3, I should do the "adding to the Form" part using callSerially() ?

2)
Can you please comment on each of the following styles of doing the same thing, note that they all seem to work.

CASE 1
public void actionPerformed()
{
new Thread(new Runnable( doBigStuff() )).start()
}

public void doBigStuff()
{
// big stuff
getMidlet.setDisplay(nextScreen)
}
The above code snippet uses "lcdui logic".. that is, offload the heavy processing in another thread, and when it is done change the screen in that same thread.

[b]OR[/b]
CASE 2
public void actionPerformed()
{
new Thread(new Runnable( doBigStuff() )).start()
}

public void doBigStuff()
{
// big stuff
callSerially(getMidlet.setDisplay(nextScreen))
}
Frankly I don't really know what the difference between the above snippet and CASE 1. It just seems "more correct" to let the EDT handle changing of the Displays... but is this how callSerially() was meant to be used?

[b]OR[/b]
CASE 3
public void actionPerformed()
{
Display.invokeAndBlock( doBigStuff() ));
getMidlet.setDisplay(nextScreen)
}

public void doBigStuff()
{
//big stuff
}
The above code snippet makes the most sense to me, and also seems like good design..but that's only thanks to Foxtrot's handy little invokeAndBlock()
Structuring my code this way would make me fully reliant on LWTUI.

Once again, thanks for your time!

Message was edited by: nafs

vprise
Offline
Joined: 2003-11-07
Points: 0

Hi Nafs,

> Are you saying that while doing step #3, I should do
> the "adding to the Form" part using callSerially() ?

Yes. Same applies to all IO including network and all long running operations etc...
This isn't very different from LCDUI which also features a callSerially method, it tries to be more threadsafe but thread safety is a pipe dream in a cross platform UI library (e.g. AWT still has thread safety.

> 2)
> Can you please comment on each of the following
> styles of doing the same thing, note that they all
> seem to work.

When you say work don't forget that you are probably running in on a simulator and very few devices if at all... Since threading works very differently across devices things fail in these cases and people are quick to blame the devices for bugs ;-)

> CASE 1
> public void actionPerformed()
> {
> new Thread(new Runnable( doBigStuff() )).start()
>
> public void doBigStuff()
> {
> // big stuff
> getMidlet.setDisplay(nextScreen)
> }
> The above code snippet uses "lcdui logic".. that is,
> offload the heavy processing in another thread, and
> when it is done change the screen in that same
> thread.

Form.show() usually works from a separate thread but sometimes doesn't I hope to improve this an make the method thread aware like repaint.
Generally however you should use callSerially when manipulating UI for proper portability, this is also true for truly potable LCDUI code as well.

> [b]OR[/b]
> CASE 2
> public void actionPerformed()
> {
> new Thread(new Runnable( doBigStuff() )).start()
>
> public void doBigStuff()
> {
> // big stuff
> callSerially(getMidlet.setDisplay(nextScreen))
> }
> Frankly I don't really know what the difference
> between the above snippet and CASE 1. It just seems
> "more correct" to let the EDT handle changing of the
> Displays... but is this how callSerially() was meant
> to be used?

The pseudo code is somewhat unclear but generally yes.

> [b]OR[/b]
> CASE 3
> public void actionPerformed()
> {
> Display.invokeAndBlock( doBigStuff() ));
> getMidlet.setDisplay(nextScreen)
> }
>
> public void doBigStuff()
> {
> //big stuff
> }
> The above code snippet makes the most sense to me,
> and also seems like good design..but that's only
> thanks to Foxtrot's handy little invokeAndBlock()
> Structuring my code this way would make me fully
> reliant on LWTUI.

This is the best way IMO too, but its somewhat difficult to explain and very LWUIT specific so its not as highlighted as the rest.

Thanks,
Shai.

Matteo Mazzotti

Hi, let me jump into this as in one of my previous post I asked more or less
a similar question:

> > Are you saying that while doing step #3, I should do the "adding to
> > the Form" part using callSerially() ?
>
> Yes. Same applies to all IO including network and all long
> running operations etc...
> This isn't very different from LCDUI which also features a
> callSerially method, it tries to be more threadsafe but
> thread safety is a pipe dream in a cross platform UI library
> (e.g. AWT still has thread safety.

As you might remember, I have a similar situation where a network thread
gets data from the server and updates a ListModel.
The update is performed by the same network Thread. I understand that
whenever a change in the underlying (default) listModel occurs, a
DataChanged event is fired. So, what does exactly happen behind the scenes?
Is EDT woken up by such event, so basically the result is the same as
calling callSerially ?

Thanks
Matteo

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
For additional commands, e-mail: users-help@lwuit.dev.java.net

Shai Almog

Hi Matteo,
> As you might remember, I have a similar situation where a network
> thread
> gets data from the server and updates a ListModel.
> The update is performed by the same network Thread. I understand that
> whenever a change in the underlying (default) listModel occurs, a
> DataChanged event is fired. So, what does exactly happen behind the
> scenes?
> Is EDT woken up by such event, so basically the result is the same as
> calling callSerially ?

Sort of yes...
The pseudo code for addItem/removeItem is something like this:

public void addItem(...) {
vector.addElement(...);
fireDataChangedEvent(...);
}

private void fireDataChangedEvent(...) {
if(!Display.getInstance().isEDT()) {
Display.getInstance.callSerially(new Runnable() {
public void run() {
fireDataChangedEvent(...);
}
});
return;
}

// loop over listeners and notify them of the event...
}

Hope this example makes it clearer.
This generally makes the model thread aware. Notice that thread aware
is NOT thread safe!
Modifying the model simultaneously from multiple threads is risky
business, but reading it from many threads while modifying it from
one thread should be OK.

Thanks,
Shai.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@lwuit.dev.java.net
For additional commands, e-mail: users-help@lwuit.dev.java.net

szczyp

I found this link in one of the threads, and have a question related to this. Didn't want to start a new topic, but if I should have, sorry for waking up this zombie.

You say that you modeled after swing. The little inconsistency I noticed after reading this and other thread posts is that you always call the listeners in EDT, whereas no such thing is done for swing. I tested this using these simple codes:
Swing:
[code]
public static void main(String[] args) {
final DefaultListModel model = new DefaultListModel();
model.addListDataListener(new ListDataListener() {

@Override
public void intervalRemoved(ListDataEvent e) {
}

@Override
public void intervalAdded(ListDataEvent e) {
System.out.println("added " + Thread.currentThread() + " " + SwingUtilities.isEventDispatchThread());
}

@Override
public void contentsChanged(ListDataEvent e) {
}
});

Thread t = new Thread() {

public void run() {
while (true) {
model.addElement("test");
try {
Thread.sleep(2000);
} catch (InterruptedException exc) {
}
}
}
};
t.start();
}
[/code]

LWUIT:
[code]
protected void startApp() throws MIDletStateChangeException {
if (!started) {
started = true;
Display.init(this);
final DefaultListModel model = new DefaultListModel();
model.addDataChangedListener(new DataChangedListener() {

public void dataChanged(int type, int index) {
System.out.println("added " + Thread.currentThread() + " " + Display.getInstance().isEdt());
}
});
Thread t = new Thread() {

public void run() {
while (true) {
model.addItem("test");
try {
Thread.sleep(2000);
} catch (InterruptedException exc) {
}
}
}
};
t.start();
}
}
[/code]
For the swing app, SwingUtilities.isEventDispatchThread() always returns false, for LWUIT, a corresponding method always returns true.
Is there any specific reason you did that for LWUIT?

Regards,
szczyp

vprise
Offline
Joined: 2003-11-07
Points: 0

This is not an accurate comparison since Swing/AWT differ in their relationship from LWUIT/MIDP.
Swing's EDT == AWT's EDT and they have a strong relation.
Thus when a native event is fired in the OS thread the AWT normalizes that event to the AWT/Swing EDT.

LWUIT can't have that relation to the MIDP event thread since the MIDP event thread has no modality (e.g. invokeAndBlock) and some devices do "weird" things with the native thread (e.g. different thread for painting/events/callbacks).
So LWUIT does pretty much the same things that the AWT peers do: it normalizes native calls to the LWUIT EDT.

Swing doesn't normalize user calls (e.g. your example of the main thread), since AWT does that for it in the peer level. This caused HUGE problems in Swing so much so that since version 1.4 Swing developers recommend that you no longer use the main thread for anything! Swing developers recommend that the main method should call invokeLater(Runnable).

LWUIT has code to normalize event dispatching and prevent race conditions, this prevents most of the errors related to threads and removes completely the need for synchronization in a LWUIT application.

So the threading model is not identical but replicating that particular behavior of Swing would be a HUGE mistake.

vprise
Offline
Joined: 2003-11-07
Points: 0

Hi,
> 1) Here is what I know about the EDT... the EDT is
> this one big massive thread which probably has a
> internal Queue. All kinds of UI activities (drawing,
> paint, flush, god knows what else) are queued and
> subsequently executed in the EDT. Based on my
> limited Swing experience, I also know that no
> "heavy" tasks should be executed in this thread.
> Fine, makes sense.

This is correct. We technically have multiple queues on the EDT but that's just a technicality.

> 2)
> While working on LCDUI, here's a simple snippet of my
> [...]
> Works like a charm.

Correct, most UI toolkits are single threaded internally to avoid complexities of race conditions between events, painting etc...

> Ok now here is the part that confuses me. While using
> LWTUI, I have something like this:
> public void [b]actionPerformed()[/b]
> {
> connectToServerAndGetFile();
> The above code works fine... why? I dont understand.
> My theory is that in the case of lcdui, there is no
> concept of EDT and hence all my tasks are happening
> in 1 big thread. Which is why I was required to call
> connectToServerAndGetFile() asynchronously (in that
> anon class code). But I dont exactly know what
> happens different in LWTUI.

Generally this won't work properly in LWUIT either... However, the LWUIT EDT is separate from the MIDP thread which means that when a call occurs on actionPerformed you are blocking LWUIT from painting/receiving actions. However MIDP can still paint and send events to LWUIT...
So it might seem that connecting to the server works properly but it doesn't really.

> 2)
> In regards to the above point, which of th following
> "styles" is considered better practice:
> public void actionPerformed()
> {
> connectToServerAndGetFile();
> [b]OR[/b]
> public void actionPerformed()
> {
> new Thread(new
> Runnable(){connectToServerAndGetFile();}}).start();

The second one is the correct one for a more responsive UI.

> 3)
> Let us look at the docs for callSerially()...
> "[i]Causes the runnable to be invoked on the event
> dispatch thread.[/i]".
> What exactly does it mean to "invoke something on the
> EDT"? Why would i want to do it? I am looking for
> scenarios where this is used.

Officially LWUIT is single threaded so all operations must be done in the LWUIT thread, technically things such as calls to repaint might work from a separate thread but since this is something that can't possibly be tested for all use cases on all devices we can't guarantee support. So if you want to manipulate the LWUIT UI you "should" do it in the EDT.

E.g. Say you opened your thread and downloaded data, then you want to update the UI on the screen. If you do it from a separate thread things break in "creative" ways so you would like your code to continue running from the EDT thread (after the other thread completes) in order to update the UI.

If you want examples of what can break... A paint might occur just as you are changing a value in a variable causing LWUIT to draw the value mid change and causing artifacts in the end result. Key presses might have a race condition with painting which might draw a component from a different form on the current form (this is very rare).

> 4)
> I dont understand what is the difference between
> callSerially() and callSeriallyAndWait()... the docs
> state, "[i]..with the added benefit of waiting for
> the method to be invoked[/i]". First of all, which
> method are they talking about here? The run() method
> of the Runnable? Again... would appreciate if someone
> could give me a practical scenario which demonstrates
> the use of these.

Yes the run method of the runnable. The use case is rather simple callSerially is useful when your thread is no longer needed and you just need to do the final processing in the EDT. callSeriallyAndBlock is used when you wish for the current state to be updated before returning, it will perform the call serially invocation and hold the current thread until run() has completed.
This is important for when you must guarantee state, e.g. the default list model can be updated from a separate thread performing downloads in the background. However, when a change happens an event must be fired.... If the event will arrive on a separate thread we might have a race condition (or worse) with the list (this is actually a bug we ran into).
So when firing a change event we need to check if the current thread is the EDT (isEDT method) and if not use callSerially... The problem with callSerially is that it would create a new race condition!
Data would be added to the model but the event won't be fired because call serially doesn't wait for the EDT to complete its work... callSeriallyAndWait will work correctly here.

(sorry if this is getting hairy)

Sample pseudo code if we were using call serially rather than call serially and wait:
add something to the model
Select the last item on the list

The second line might fail sometimes since adding to the model might not have time to notify the list of the change causing a potential error.

BTW both methods map to the swing method of SwingUtilities.invokeLater() and SwingUtilities.invokeAndBlock() although the naming convention callSerially is taken from MIDP's Display.

> 5)
> Ok now I will try to connect two dots of my
> understanding...
> In one of my earlier points (#2), I demonstrated how
> connectToServerAndGetFile() worked inside
> actionPerformed() whether invoked asynchronously or
> synchronously. The reason for this is because
> actionPerformed() is not invoked on the EDT. Ok
> good.
> So... then WHY does the following code fail:
> public void actionPerformed()
> {
> Display.getInstance().callSerially( new
> Runnable(){connectToServerAndGetFile()}));

Action performed is called on the EDT ;-)

Thanks, these were very good questions on a very complex matter and I'm sure the questions and answers will be helpful to others.

Shai.

nafs
Offline
Joined: 2008-06-10
Points: 0

Hi again,

Before I begin to completely digest your post, I have a quick question...
You say, [i]"it [callSeriallyAndWait()] will perform the call serially invocation [b]and hold the current thread until run()[/b] has completed".[/i]

hmm... in that case, would you agree that the docs are slightly misleading:
"[i]...with the added benefit of waiting for the method to be invoked[/i]", should instead be,
"[i]...with the added benefit of waiting for the Runnable to be [b]completed[/b][/i]"

vprise
Offline
Joined: 2003-11-07
Points: 0

> hmm... in that case, would you agree that the docs
> are slightly misleading:

Agreed, will be in the next drop ;-)

Thanks,
Shai.