×

Discussion Board

Results 1 to 13 of 13
  1. #1
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Lightbulb possible bug with Thread.join() ?

    I have come over a strange behavior with Thread.join(): on some Nokia models, it takes much longer than, IMHO, it should.

    I am attaching a simple Midlet to verify this alleged issue; as you can see, the Midlet simply creates a Thread ( which does nothing, just sleeps ), then switches the Thread off ( mRunning=false ), waits for it to finish ( Thread.join() ) and then displays an Alert showing how many milliseconds the joining() took.

    Now, on about half Nokia models, on all SE, Samsungs and LGs ( and I've tested quite a few using Virtual Developer Lab ), in Sun's emulator the joining() takes about 80-100ms, and that value is IMHO to be expected.

    However, on another half of Nokia phones, the joining() consistently takes about 1000-1050 ms. It is my suspicion that on those models, join() internally sleeps for exactly 1 second.

    List of Nokia models that I have tested and which display correct behavior:
    3120, 5230, 5320 Xpress, 6710 Nav, 5630 Xpress, E52, E55, E72, N78, N79, N85, N96, N97, N97 mini

    Models that behave incorrectly:
    5500 Sport, 5700 Xpress, 6110 Nav, 6120 Classic, E51, E61, E63, E65, E66, E70, E71, N73, N80, N81, N82, N90, N95

    Could anyone enlighten me what's going on here?

    Midlet to verify the issue ( note that it is called 'E71ThreadJoin' because I initially saw this issue on E71 ):
    Code:
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    
    public class E71ThreadJoin extends MIDlet implements Runnable
      {
      private Display mDisplay;
      private Alert mInfoAlert;
      private Thread mSleepingThrd = null;
      private boolean mRunning = false;
    
      public E71ThreadJoin()
        {
        mRunning = true;
        mSleepingThrd = new Thread(this);
        mSleepingThrd.start();
        }
    
      public void startApp()
        {
        mDisplay = Display.getDisplay(this);
    
        long startTime = System.currentTimeMillis();
    
        mRunning = false;
        try { mSleepingThrd.join(); }
        catch(InterruptedException ex) {}
    
        mInfoAlert = new Alert("E71 Thread.join()",
            (System.currentTimeMillis()-startTime)+" ms",
            null,
            AlertType.INFO);
    
        mDisplay.setCurrent(mInfoAlert);
    
        try { Thread.sleep(2000); }
        catch (InterruptedException ex) {}
    
        notifyDestroyed();
        }
    
      public void run()
        {
        while( mRunning )
          {
          try { Thread.sleep(100); }
          catch(InterruptedException ex) {}
          }
        }
    
      public void pauseApp() { }
      public void destroyApp(boolean unconditional) {}
      }

  2. #2
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: possible bug with Thread.join() ?

    Does it make a difference if you declare mRunning as volatile?

    You do need to be careful with Thread.join()... if you inadvertantly join a thread to itself, some phones do nothing (join() returns immediately), while others will deadlock. People tend to fall for this trap when using join() in some part of the code that can be invoked by different threads... usually they've called Thread.join() inside destroyApp(), forgetting that they call destroyApp() from inside their own exit code.

    Graham.

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by grahamhughes View Post
    Does it make a difference if you declare mRunning as volatile?
    Good point; I've tried and it does not make one bit of difference. Still exactly the same set of models take more than 1000 ms while others take 50-100 ms.
    In fact, I can even eliminate the 'mRunning' variable altogether and results are still the same:
    Code:
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    
    public class E71ThreadJoin extends MIDlet implements Runnable
      {
      private Display mDisplay;
      private Thread mSleepingThrd = null;
    
      public E71ThreadJoin()
        {
        mSleepingThrd = new Thread(this);
        mSleepingThrd.start();
        }
    
      public void startApp()
        {
        mDisplay = Display.getDisplay(this);
    
        long startTime = System.currentTimeMillis();
    
        try { mSleepingThrd.join(); }
        catch(InterruptedException ex) {}
    
        long endTime = System.currentTimeMillis();
    
        Alert mInfoAlert = new Alert("Thread.join()", (endTime-startTime)+" ms", null, AlertType.INFO);
        mDisplay.setCurrent(mInfoAlert);
    
        try { Thread.sleep(2000); }
        catch (InterruptedException ex) {}
    
        notifyDestroyed();
        }
    
      public void run()
        {
        try { Thread.sleep(100); }
        catch(InterruptedException ex) {}
        }
    
      public void pauseApp() { }
      public void destroyApp(boolean unconditional) {}
      }


    Quote Originally Posted by grahamhughes View Post
    You do need to be careful with Thread.join()... if you inadvertantly join a thread to itself, some phones do nothing (join() returns immediately), while others will deadlock. People tend to fall for this trap when using join() in some part of the code that can be invoked by different threads... usually they've called Thread.join() inside destroyApp(), forgetting that they call destroyApp() from inside their own exit code.
    All that is true, but how does it relate to the situation at hand? Does the midlet above make this mistake?

  4. #4
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by Utumn0 View Post
    All that is true, but how does it relate to the situation at hand? Does the midlet above make this mistake?
    No, I just thought it was worth mentioning.

    Your code does contain an assumption: that at the point join() is called, the thread execution has actually started.

    Try:

    PHP Code:
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;

    public class 
    Join extends MIDlet implements CommandListenerRunnable {

        private static final 
    Command EXIT = new Command("Exit"Command.EXIT, 1);

        private 
    Form form;

        public 
    void startApp() {
            if (
    form == null) {
                
    form = new Form("Join");
                
    form.addCommand(EXIT);
                
    form.setCommandListener(this);
                
    Thread t = new Thread(this);
                
    time("Start thread");
                
    t.start();
                try {
                    
    t.join();
                } catch (
    InterruptedException e) {
                    
    // ignore
                
    }
                
    time("Thread death");
            }

            
    Display.getDisplay(this).setCurrent(form);
        }

        public 
    void pauseApp() {
        }

        public 
    void destroyApp(boolean unconditional) {
        }

        private 
    synchronized void time(String s) {
            
    form.append(": " System.currentTimeMillis() + "\n");
        }
        
        public 
    void commandAction(Command cmdDisplayable disp) {
            if (
    cmd == EXIT) {
                
    notifyDestroyed();
            }
        }

        public 
    void run() {
            
    time("Enter run()");
            try {
                
    Thread.sleep(100);
            } catch (
    InterruptedException e) {
                
    // ignore
            
    }
            
    time("Exit run()");
        }

    I don't have any of the devices from your "fail" list to try this myself.

    It would also be worth changing the code to use two threads instead of one, and have the join() in the second thread, thus removing it from the event queue. Realistically, you'd want to avoid callig join() from an event anyway, since you want event methods to return as quickly as possible.

    Graham.

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    One can test using Remote Device Access.

    The only real devices I have been testing on are the 3120, 6710, SE 700i ( where is takes 100ms) and E71 ( where it takes 1000ms, i.e. 'fails')

    I have a real-world example which has two threads, does not call join() from a handler, and which fails on E71 ( that's how I found out about this issue )

    Believe me, in my real-world example the Thread I join() for sure has started. But I will try your code...

  6. #6
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    I have tested your midlet using N79, E63 and 5500 Sport in Remote Device Access.

    The results are the same: as expected, on the 'working' model ( N79 ) the time between 'Enter run()' and 'Thread death' is about 100ms.
    On the 'non working' models this time is always slightly larger than 1000ms.

  7. #7
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by Utumn0 View Post
    One can test using Remote Device Access.
    Sure, but it would take longer and I can't be bothered. You have the appropriate handset available, so that's much faster to test.

    Quote Originally Posted by Utumn0 View Post
    I have a real-world example which has two threads, does not call join() from a handler, and which fails on E71 ( that's how I found out about this issue )

    Believe me, in my real-world example the Thread I join() for sure has started. But I will try your code...
    I believe you, but I can only comment on the code I've actually seen.

    There appears to be two possibilities:

    1. join() always takes at least one second due to some implementation quirk

    2. Some aspect of your code (of which you're not aware) is resulting in a delay

    The first thing to do is come up with some code that eliminates all possibility of (2). Doing that will either find the problem for you, or provide you with a solid platform for devising and testing workarounds if (1) proves to be the case.

    Graham.

  8. #8
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by Utumn0 View Post
    I have tested your midlet using N79, E63 and 5500 Sport in Remote Device Access.

    The results are the same: as expected, on the 'working' model ( N79 ) the time between 'Enter run()' and 'Thread death' is about 100ms.
    On the 'non working' models this time is always slightly larger than 1000ms.
    And.. the time between "Exit run()" and "Thread death" is about 900ms?

  9. #9
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by grahamhughes View Post
    There appears to be two possibilities:
    1. join() always takes at least one second due to some implementation quirk
    2. Some aspect of your code (of which you're not aware) is resulting in a delay
    I agree.
    Quote Originally Posted by grahamhughes View Post
    The first thing to do is come up with some code that eliminates all possibility of (2). Doing that will either find the problem for you, or provide you with a solid platform for devising and testing workarounds if (1) proves to be the case.
    I think we already came up with this code: your midlet. I , for one, cannot see anything wrong with it, and I hope you also cannot
    I already have a workaround for my 'real-world' midlet; I am posting this mainly in hope that someone from Nokia notices and corrects this.

  10. #10
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by grahamhughes View Post
    And.. the time between "Exit run()" and "Thread death" is about 900ms?
    working device:
    Code:
    Start thread: 1260711861983
    Enter run():  1260711862004   // +11
    Exit run():   1260711862137   // +144
    Thread death: 1260711862141   // +148
    non-working device:
    Code:
    Start thread: 1260834454503   
    Enter run():  1260834454518   // +15
    Exit run():   1260834454650   // +132
    Thread death: 1260834455574   // +1071

  11. #11
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by Utumn0 View Post
    I , for one, cannot see anything wrong with it, and I hope you also cannot
    Hmmm... I always assume my code is probably broken, but aside from a possible interaction between a user thread and the event thread, I think we're on the money.

    Quote Originally Posted by Utumn0 View Post
    working device:
    Code:
    Start thread: 1260711861983
    Enter run():  1260711862004   // +11
    Exit run():   1260711862137   // +144
    Thread death: 1260711862141   // +148
    non-working device:
    Code:
    Start thread: 1260834454503   
    Enter run():  1260834454518   // +15
    Exit run():   1260834454650   // +132
    Thread death: 1260834455574   // +1071
    Yes... that's pretty compelling.

    The only other experiment I can think of is to sleep for a couple of seconds before the join(), to see if it's the join() itself that adds the time, or if the thread doesn't register as being dead until some time after the run() method exits. Though, I'm not sure it helps you to know...

    What's your workaround? wait()/notify()?

  12. #12
    Registered User
    Join Date
    May 2009
    Posts
    29

    Re: possible bug with Thread.join() ?

    Quote Originally Posted by grahamhughes View Post
    What's your workaround? wait()/notify()?
    In my case, it turned out that with a slight modification of the code I did not have to call join() at all.
    But many others may not be so lucky.

  13. #13
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: possible bug with Thread.join() ?

    I have slightly modified Graham's midlet:
    PHP Code:
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;

    public class 
    Join extends MIDlet implements CommandListenerRunnable {

        private static final 
    Command EXIT = new Command("Exit"Command.EXIT, 1);
        private 
    long startTime;
        private 
    Form form;

        public 
    void startApp() {
            if (
    form == null) {
                
    form = new Form("Join");
                
    form.addCommand(EXIT);
                
    form.setCommandListener(this);
                
    Thread t = new Thread(this);
                
    startTime System.currentTimeMillis();
                
    t.start();
                try {
                    
    Thread.sleep(500);
                } catch (
    InterruptedException e) {
                    
    // ignore
                
    }
                try {
                    
    t.join();
                } catch (
    InterruptedException e) {
                    
    // ignore
                
    }
                
    time("Thread death");
            }

            
    Display.getDisplay(this).setCurrent(form);
        }

        public 
    void pauseApp() {
        }

        public 
    void destroyApp(boolean unconditional) {
        }

        private 
    synchronized void time(String s) {
            
    form.append(": " + (System.currentTimeMillis()-startTime) + "\n");
        }

        public 
    void commandAction(Command cmdDisplayable disp) {
            if (
    cmd == EXIT) {
                
    notifyDestroyed();
            }
        }

        public 
    void run() {
            
    time("Enter run()");
            try {
                
    Thread.sleep(100);
            } catch (
    InterruptedException e) {
                
    // ignore
            
    }
            
    time("Exit run()");
        }

    and now on both 'working' and 'non-working' devices, the results are the same:

    Enter run(): ~ 0
    Exit run(): ~ 100-150
    Thread Death: ~ 500-550

    That IMHO proves the following:

    1) the thread DID register itself as dead within the 400ms
    2) if a thread being joined() is already dead, join() always returns immediately.

    Furthermore, juggling the sleeping times we can see that the join() always rounds up the time to the nearest second.
    So now the bug looks like this: on 'non-working' devices, Thread.join() checks if the thread is dead only once per second.
    Last edited by Utumno; 2009-12-14 at 10:33.

Similar Threads

  1. Bug reporting: closed?
    By AndrzejPeszynski in forum Feedback - Nokia Developer Services & Infrastructure
    Replies: 1
    Last Post: 2009-12-12, 13:51
  2. RecordStore bug on Series 60
    By ncerezo2 in forum Mobile Java General
    Replies: 21
    Last Post: 2009-11-26, 10:12
  3. A bug: setColor with offscreen graphics - PLEASE, REPLY THIS TIME
    By palmcrust in forum Mobile Java General
    Replies: 11
    Last Post: 2003-12-04, 12:43
  4. Firmware bug or code bug displaying list on 3650
    By blackjack75 in forum Mobile Java General
    Replies: 2
    Last Post: 2003-09-24, 19:52
  5. Replies: 8
    Last Post: 2003-07-11, 12:56

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×