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 № 1dlaczego 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());
}