/ / Wątek blokuje się na BlockingQueue.take bez wyraźnego powodu - Java, Android, Concurrency, Android-NDK

Wątek utknął na BlockingQueue.take bez wyraźnego powodu - java, android, współbieżność, android-ndk

Natknąłem się na naprawdę dziwny problem, którego nie rozumiem. Najpierw trochę historii:

Próbuję uruchomić JavaScriptCore i używać go jakoswego rodzaju język skryptowy dla aplikacji na Androida. Problem w tym, że rozmiar stosu w głównym wątku jest dość ograniczony w starszych wersjach Androida (coś takiego jak 12k w API 16). Jednak nadal chciałbym zadzwonić do JS w głównym wątku, poprosić o oddzwonienie, aby zażądać różnych rzeczy i aby wszystko to wyglądało synchronicznie. Nie ma problemu - wyciągnę parę channe ... khm ... SynchronousQueues i odbijam wykonanie tam iz powrotem. Oto jak wygląda mój kod.

To całkiem proste - za każdym razem, gdy coś dzwoniodłóż - odbija się do drugiego wątku i stamtąd kontynuuje. Jedynym problemem jest, no cóż, to nie działa. W prawdziwym przypadku użycia z kodem JavaScript w pewnym momencie po prostu zawiedzie całkiem niezawodnie, choć nie w tym samym miejscu dla emulatora i różnych urządzeń. Logcat zawsze wygląda całkiem nieszkodliwie:

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

Jednak ta druga WYKONANIE nigdy nie zostanie odebraneco do zasady, mimo że put przechodzi. O ile rozumiem, nie powinno to być nawet możliwe z kolejkami synchronicznymi. Patrząc na zrzut wątku, wątek w tle czeka w pętli uruchamiania na następną wiadomość, podczas gdy główny stoi zaparkowany na przychodzącym. Weź. Żadne inne wątki nie wchodzą w interakcje z tym.

Na jednym z moich urządzeń mogłem skonfigurować warunekpunkt przerwania na dokładny moment, w którym to przestaje działać, i mógłbym zatrzymać go, gdy GŁÓWNY czeka na komunikat WYKONAJ. Wiadomość jest różna od zera, kolejka pierwszego planu w tym momencie działa, mogę sondować ją z czasem oczekiwania lub bez w Android Studio, wziąć jego rozmiar, cokolwiek. Jak tylko przejdę przez wszystkie operacje zawiesić.

Oczywiście podejrzewałem shenanigany JNI, ale w Logcat nie ma żadnych zrzutów pamięci, błędów segmentacji ani żadnych ostrzeżeń.

Ponadto nie jest to tylko zajęcie - nawet jeśli robię to z naprawdę brudnym zajęciem oczekiwania:

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

Main utknął w ankiecie, wątek w tle wesoło odpycha drugą kolejkę co 20 milisekund.

Próbowałem zagnieżdżać odroczenia z naprawdę leniwym silnikiem, który lubi dużo spać i nie ma problemu z przejściem 200 głębokich, pomimo przepełnienia liczb całkowitych:

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));
}

...

To, co chyba najdziwniejsze, to tonie ma znaczenia, jakiej synchronizacji używam. SynchronizedQueue, ArrayBlockingQueue, LinkedBlocking kolejka - zawsze kończy się niepowodzeniem w tym samym miejscu z dokładnie tym samym zrzutem wątku. Do diabła, nawet stworzyłem własny wymiennik tylko po to, żeby zobaczyć, że nie oszaleję i wciąż utknąłem w ten sam sposób.

Więc tak, jestem kompletnie zakłopotany. Jakieś pomysły, co się dzieje? Jakakolwiek pomoc w debugowaniu tego będzie bardzo mile widziana.

Odpowiedzi:

1 dla odpowiedzi № 1

dlaczego używasz wątku. Istnieją również alternatywy dla wątku. Spróbuj użyj tego: może być jego dziełem

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());

}