Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
Developer
Jeff_Lu
Posts: 384
Registered: ‎08-12-2008
My Device: 8700
Accepted Solution

what will cause 'notify() and wait()' mechanism not working any more?

Hi All,

 

My application has been working for a couple of years unless user recenlty upgrade OS7.1 and try my new feature, all of sudden, there is part not working properly.

 

Appplcaition will download mass data from server, long story to short, 

 

when there is no download queue, application will wait until there is real download request.

 

 

 

my code something like the follow:

        InvokeContainer c = new InvokeContainer(r);
        synchronized (c.syncObj) {
            // push to queue
            synchronized (_queue) { _queue.addElement(c); }
            LogManager.getInstance().add("Notify queue Thread _queue size " + _queue.size());
            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
            // wait for release
           // LogManager.getInstance().add("Invoke data wait to release");
            //synchronized(c.syncObj){
                try { c.syncObj.wait(); } catch (Exception ex) {}
            //}
            LogManager.getInstance().add("Invoke data released");
        }

 

        while (!_stop) {
            InvokeContainer c = null;

            // wait for invoke
            c = getNextInvoke();
            if (c == null) {
                LogManager.getInstance().add("Wait For next queue");
                synchronized (_queueSyncObj) { 
                    try { 
                        _queueSyncObj.wait(); 
                        LogManager.getInstance().add("Invoked");
                    } catch (Exception ex) {
                        LogManager.getInstance().add("Exception happened: " + ex.toString());
                    } 
                }
                c = getNextInvoke();
                LogManager.getInstance().add("Get a new queue ");
            }

 

My question is:

 

my application always stop at:

 

 LogManager.getInstance().add("Notify queue Thread _queue size " + _queue.size());

and I saw there is one queue waiting, however, the line after wait() never called.

 

what will cause notify() not invoking wait()?

 

 

 

 

 

 

Developer
Jeff_Lu
Posts: 384
Registered: ‎08-12-2008
My Device: 8700

Re: what will cause 'notify() and wait()' mechanism not working any more?

more information to check,

 

If I connect device to debug, it never happen...:smileymad:

Developer
peter_strange
Posts: 19,609
Registered: ‎07-14-2008
My Device: Not Specified

Re: what will cause 'notify() and wait()' mechanism not working any more?

I'm not the best person on the forum for this sort of thing, but I will try to help. 

 

Can you describe, in words, the function of the each of the synchronized blocks that you have and how these interelate?  You seem to have more things going on here than you really need and I am a bit confused. 

 

You say that you see this message:

            LogManager.getInstance().add("Notify queue Thread _queue size " + _queue.size());
can you telll if the processing is stopped here:

            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
or here?
                try { c.syncObj.wait(); } catch (Exception ex) {}.

 

Also I have a memory that if you any notify that is issued before a wait has no effect, so perhaps there is race condition if the notify for

_queueSyncObj

occurs after this:

c = getNextInvoke();

but before this:

synchronized (_queueSyncObj)

 

Perhaps this can be resolved by changing your code to the following:

            if (c == null) {
                LogManager.getInstance().add("Wait For next queue");
                synchronized (_queueSyncObj) {

c = getNextInvoke();

if ( c == null ) {
                    try {
                        _queueSyncObj.wait();
                        LogManager.getInstance().add("Invoked");
                    } catch (Exception ex) {
                        LogManager.getInstance().add("Exception happened: " + ex.toString());
                    }
}

                }
if ( c == null ) {

                c = getNextInvoke();
}

                LogManager.getInstance().add("Get a new queue ");
            }

 

Developer
Jeff_Lu
Posts: 384
Registered: ‎08-12-2008
My Device: 8700

Re: what will cause 'notify() and wait()' mechanism not working any more?

Thanks peter,

 

I will try and let you know it.

 

 

>>can you telll if the processing is stopped here:

>>            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }

 

Yes, it stops here.

 

>>Also I have a memory that if you any notify that is issued before a wait has no effect, so perhaps there is race >>condition if the notify for

 

That is a great spark.

 

Thanks,

Jeff

 

 

Developer
peter_strange
Posts: 19,609
Registered: ‎07-14-2008
My Device: Not Specified

Re: what will cause 'notify() and wait()' mechanism not working any more?

If it is stopping here:

 

synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }

 

then logically this can only happen if it can not get the _queueSyncObj Object becuase something else has it.  In the code you have supplied, this can only happen between these two statements:

 

                synchronized (_queueSyncObj) {
                    try {
                        _queueSyncObj.wait();

 

which seems very unlikely.  So perhaps there is something else synchronizing on this object?

Developer
Jeff_Lu
Posts: 384
Registered: ‎08-12-2008
My Device: 8700

Re: what will cause 'notify() and wait()' mechanism not working any more?


public class IPCThread {

    // Server instance

    private static final long GUID = 0x2add398bf534e864L; // 

    public static synchronized IPCThread getServerInstance() {
        IPCThread res = null;
        for (int i = 0 ; i < 600; i++) {
            synchronized (GlobalSync.getSyncObj(GUID)) {
                res = (IPCThread)RuntimeStore.getRuntimeStore().get(GUID);
            }
            if (res != null)
                break;
            try { Thread.sleep(100); } catch (Exception ex) { }
        }
        return res;
    }

    public static synchronized IPCThread initServerInstance() {
        synchronized (GlobalSync.getSyncObj(GUID)) {
            RuntimeStore rs = RuntimeStore.getRuntimeStore();
            IPCThread res = new IPCThread();
            rs.put(GUID, res);
            res.start();
            return res;
        }
    }

    // Client instance

    private static IPCThread _instance = null;

    public static synchronized IPCThread getInstance() {
        if (_instance == null) {
            _instance = new IPCThread();
            _instance.start();
        }
        return _instance;
    }

    ////////////////////////////////////////////////////////////////////////////////

    private boolean _stop;
    private Vector _queue;
    private Object _queueSyncObj;
    private String _moduleName;
    private int _pid;

    private IPCThread() {
        super();
        _stop = false;
        _queue = new Vector();
        _queueSyncObj = new Object();
        _moduleName = SysUtils.currentModuleName();
        _pid = SysUtils.currentPid();
    }

    private void start() {
        ThreadEx t = new ThreadEx(
            new Runnable() { public void run() { runThread(); } },
            "IPCThread"
        );
        try {
            t.start();
        }
        catch (ThreadStartException ex) {
            SystemLog.getInstance().addMessage("Cannot start IPC thread immediately");
            t.startAllowDelayed();
        }
    }

    private void stop() {
        _stop = true;
        synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
    }

    private InvokeContainer getNextInvoke() {
        synchronized (_queue) {
            if (_queue.size() == 0)
                return null;
            InvokeContainer res = (InvokeContainer)_queue.elementAt(0);
            _queue.removeElementAt(0);
            return res;
        }
    }

    private void runThread() {
        while (!_stop) {
            InvokeContainer c = null;

            // wait for invoke
            c = getNextInvoke();
            if (c == null) {
                synchronized (_queueSyncObj) { try { _queueSyncObj.wait(); } catch (Exception ex) {} }
                c = getNextInvoke();
            }
            if (c == null)
                continue;

            // invoke
            try {
                c.res = c.r.run();
            }
            catch (Exception ex) {
                c.ex = ex;
            }

            // release caller thread
            synchronized (c.syncObj) { c.syncObj.notify(); }
        }
    }

    private static class InvokeContainer {
        public IPCThreadTask r;
        public Object syncObj;
        public Object res;
        public Exception ex;
        public InvokeContainer(IPCThreadTask r) {
            this.r = r;
            this.syncObj = new Object();
            this.res = null;
            this.ex = null;
        }
    }

    // Interface

    public String getModuleName() {
        return _moduleName;
    }

    public Object invoke(IPCThreadTask r) throws Exception {
        if (_pid == SysUtils.currentPid()) {
            // no need to invoke, call directly
            return r.run();
        }

        InvokeContainer c = new InvokeContainer(r);
        synchronized (c.syncObj) {
            // push to queue
            synchronized (_queue) { _queue.addElement(c); }
            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
            // wait for release
            try { c.syncObj.wait(); } catch (Exception ex) {}
        }
        // check for errors
        if (c.ex != null)
            throw c.ex;
        return c.res;
    }

    public void invokeAsync(IPCThreadTask r) {
        InvokeContainer c = new InvokeContainer(r);
        synchronized (c.syncObj) {
            // push to queue
            synchronized (_queue) { _queue.addElement(c); }
            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
        }
    }
}

 Thanks Peter,

 

I have updated my full source code,  I can see there are two locations holds _queueSyncObj, however, it might happen on the second call.

invokeAsync()

Developer
peter_strange
Posts: 19,609
Registered: ‎07-14-2008
My Device: Not Specified

Re: what will cause 'notify() and wait()' mechanism not working any more?

[ Edited ]

To me, in places your code seems too complicated for what it is trying to achieve.  Let me try to simplify it.

 

Firstly you have loads of protection around your creation of a Singleton RuntimeStore object.  This seems to me to be unnecessary.  Have a look at this:

http://supportforums.blackberry.com/t5/Java-Development/Create-a-singleton-using-the-RuntimeStore/ta...

 

Going through your code I would question the following:

 

1) public static synchronized IPCThread getServerInstance() {

why is this synchronized?  Stropping multiple people getting at this offers no additional protection. 

 

2) synchronized (GlobalSync.getSyncObj(GUID)) ..

this synchronized block offers no additional protection either.  Either the

IPCThread will be in there or it won't, there is no possibility of a race condition causing you a problem here.

 

3)  public static synchronized IPCThread initServerInstance() {
        synchronized (GlobalSync.getSyncObj(GUID)) {

Here there might be some value in having only one person create this at a time.  But if this was an issue, then the second person through should check to see if it has been created, which this code does not do.  So every invocation of

initServerInstance()

will create and start a new IPCThread.  The synchronized are totally redundant and you have a potential hole in your processing.

 

4) public static synchronized IPCThread getInstance() {

you have another way of getting an IPCThread, which in fact will not be the same as the above and moreover, will be different if you start a different instance of your Application, for example an alternate entry or start-up variant.

 

I recommend that you replace all of these with a single getInstance() method based on the KB article.  Have it start the IPCThread if it creates it. 

 

OK, I appreciate that you don't think this is related to your problem, but with the code you have, there could be multiple IPCThreads and that wouldn't help.

 

Now onto your invocation code.

 

Can you please remove the static from the following:

private static class InvokeContainer..

AFAIK, it does not buy you anything in this circumstance, and it confuses me. 

 

The idea here seems to be that you can supply a Runnable to this process, which it will run and then notify the waiting task (if required).  You package the Runnable in an InvokeContainer. 

 

The first thing to look at is how you are extracting entries from the queue.  Here you are protecting the queue with this:

synchronized (_queue)

 

So what you are saying to me here is that you will protect this processing by protecting access to the _queue.  Something will be adding to the queue. or something will be taking it off the queue, they both can't be happening at the same time.  That is OK.

 

So how do you add to the queue?

 

Ignoring the code that will process if the process id is the same, we have this:

        InvokeContainer c = new InvokeContainer(r);
        synchronized (c.syncObj) {
            // push to queue
            synchronized (_queue) { _queue.addElement(c); }
            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }
            // wait for release
            try { c.syncObj.wait(); } catch (Exception ex) {}
        }

 

Now we have already seen the queue is protected using "synchronized (_queue)".  But this code will not prevent the entry we have just added being picked up before we process the notify - in other words, the notify might not be heeded.  But that is OK.  The other way round is not.  If the Thread that is processing the IPCThread code is at this point:

if (c == null) {

and the Thread that processing the add, executes both these statements:

            synchronized (_queue) { _queue.addElement(c); }
            synchronized (_queueSyncObj) { _queueSyncObj.notifyAll(); }

then the IPCThread will miss the notify.

 

To correct this, I would do what I have suggested previously.

 

Moving on, this looks very odd:

        InvokeContainer c = new InvokeContainer(r);
        synchronized (c.syncObj) {...}

 

but in fact this means that the code will never miss the IPCThread processing this Runnable, since the notify

synchronized (c.syncObj) { c.syncObj.notify(); }

can't be run until this Thread is waiting.  This is a good thing. 

 

So that only leaves one thing to discuss - the.invokeAsync.  This code looks fine, though the

synchronized (c.syncObj) {...}

is completely redundant. 

 

Summary - 2 recommendations:

a) Change your Singleton IPCThread to use the RuntimeStore method suggested in the KB article

b) Check inside the protection of

synchronized (_queueSyncObj) {

that

c = getNextInvoke();

is still null.

 

Finally, have you thought about putting a delay time in your waits, so that regardless of activity or not, the Thread will look for work every now and again?  For example:

_queueSyncObj.wait(1000);

 

Edit: Minor typo and readability corrections...

Developer
Jeff_Lu
Posts: 384
Registered: ‎08-12-2008
My Device: 8700

Re: what will cause 'notify() and wait()' mechanism not working any more?

Thanks Peter for your reviewing my code.

 

I'd appreciate all your idea on my code. it great help.

 

I have thinking about to put wait time there before. since my project has more than 7 modules, all rely on this fundmental downloading processing.

 

if i put wait time there, it will cause battery issue, since that thread is running all the way.

 

and i so appreciate your hint,
also I have a memory that if you any notify that is issued before a wait has no effect, so perhaps there is race condition if the notify for

 

and yes, I have catch it this happened during my debug.

 

I will do more to let you know.