Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread getting stuck on BlockingQueue.take for no apparent reason

I've stumbled upon a really weird problem that I can't make any sense of whatsoever. A little bit of backstory first:

I'm trying to run JavaScriptCore and using it as a scripting language of sorts for an Android app. The trouble is, stack size on the main thread is quite limited on older Android versions (something like 12k on API 16). However, I would still like to call into JS on the main thread, have it call back to request things and have all of that appear synchronous. No problem - I'll whip out a couple of channe... khm... SynchronousQueues and bounce the execution back and forth. Here's what my code looks like.

It's pretty simple - every time something calls defer - it bounces to the other thread and continues from there. The only problem is, well, it doesn't work. On a real use case with executing Javascript code it just fails pretty reliably at some point, though not at the same spot for the emulator and different devices. Logcat always looks pretty innocuous:

I/JavaScriptCore: Lockstep [Main]: Defer
I/JavaScriptCore: Lockstep [Main]: Send EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Receive EXECUTE_FUNC
I/JavaScriptCore: Lockstep [Background]: Defer
I/JavaScriptCore: Lockstep [Background]: Send EXECUTE_FUNC

However, that second EXECUTE never gets received by main, even though the put goes through. As far as I understand it, that should not even be possible with Synchronous queues. Looking at the thread dump, the background thread is waiting in the run loop for the next message, while main is sitting parked on incoming.take. No other threads are interacting with this.

On one of my devices I could set up a conditional breakpoint for the exact moment that this stops working, and I could pause it just as MAIN is waiting for that EXECUTE message. The message is non-null, the foregroundQueue at that point is working, I can poll it with or without timeout from Android Studio, take its size, whatever. As soon as I step over all the operations hang.

Of course, I suspected JNI shenanigans, but there are no memory dumps, segmentation faults or any warnings at all for that matter in Logcat.

Also, it's not just take - even if I do it with a really dirty busy wait:

Message msg = incoming.poll();
if(msg == null) {
 Thread.sleep(20);
 continue;
}

Main is stuck on poll, the background thread keeps merrily chugging away on the other queue every 20 milliseconds.

I tried nesting defers with a really lazy factorial that likes to sleep a lot and it has no problem going 200 deep, integer overflows notwithstanding:

LockstepThread t = new LockstepThread();

int deferredFactoriel(final int n) {
  if(n == 0) {
    return 1;
  }
  return n * t.defer(new Functor<Integer>() {
    @Override
     public Integer call() {
       try {
         Thread.sleep(20);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       return deferredFactoriel(n-1);
    }
  });
}

@Override
public void onCreate() {

  super.onCreate();

  for(int i=0; i<200; ++i) {
    Log.i("Test", i+"! = " + deferredFactoriel(i));
  }

...

What is probably strangest of all, is that it doesn't matter what synchronisation I use. SynchronizedQueue, ArrayBlockingQueue, LinkedBlocking queue - it always fails at the same spot with the exact same thread dump. Hell, I even made my own exchanger just to see that I'm not going insane and it still got stuck in the same way.

So yeah, I'm completely stumped. Any ideas what's going on? Any help with debugging this would be much appreciated.

like image 786
IvoDankolov Avatar asked Apr 28 '16 01:04

IvoDankolov


People also ask

Is BlockingQueue thread-safe?

BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control.

Is BlockingQueue concurrent?

concurrent. BlockingQueue , represents a queue which is thread safe to put elements into, and take elements out of from. In other words, multiple threads can be inserting and taking elements concurrently from a Java BlockingQueue , without any concurrency issues arising.

How does BlockingQueue work internally?

A thread trying to enqueue an element in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more elements or clearing the queue completely. Similarly, it blocks a thread trying to delete from an empty queue until some other threads insert an item.

What is the remaining capacity of BlockingQueue?

If remaining Capacity of BlockingQueue is equal to the size of the Queue, then no element can be removed from the queue because in such situation queue is empty. In any other case, Capacity is always equal to a difference between the initial capacity of this BlockingQueue and the current size of this BlockingQueue.


1 Answers

why are you using thread. There is also alternates for thread. Try to use like this:may be its works

static Timer timer;
    private TimerTask timerTask;


try {
                timer = new Timer();
                    timerTask = new TimerTask() {

                        @Override
                        public void run() {
                        }
                        }
                    };
                    timer.schedule(timerTask, 4000);
                } else {
                     timer.cancel();
                    // timer.purge();
                    MainHomeActivity.appendLogSocket("UPDATE RECEIVER : ",
                            "TIMER STOPED");

                }
            } catch (Exception e) {
Log.e(      "Socket update receiever error: ", e.toString());

            }
like image 151
parik dhakan Avatar answered Nov 06 '22 23:11

parik dhakan