Actor/message-passing within threaded Game "event loop" - android

I am building an Android application (using Scala 2.9) and am using a Thread that renders to a SurfaceView; this is for a game so it should update as often as it can. I imagine this issue is similar to other game "event loops" where the input comes from a different thread.
Here is a gross approximation of the current approach that relies on synchronization. It "works well enough", but I have general misgivings about having to use explicit synchronization and "tying up" the View/input thread.
View, "UI thread":
def View.onTouchEvent(e) { // on UI thread
Game.handleInput(e)
}
Game, "Game Thread":
def Game.handleInput(e) = S synchronized { // on UI thread
alterStateBasedOnInput
}
def Game.run () { // on Game thread
while (running) {
S synchronized {
doGameStuff
}
View.post(someStateRelayedViaRunnable)
yield
}
}
Instead of explicitly using synchronization, I'd like to have something like this:
def View.onTouchEvent(e) { // on UI thread
Game.sendMessage(e)
}
def Game.run () { // on Game thread
while (running) {
processMessage
doGameStuff
View.sendMessage(someState) // hopefully same as Game.sendMessage
yield
}
}
Now, this is relatively easy to implement manually using a ConcurrentLinkedQueue or similar, but I would really not like to reinvent the wheel here. In addition, it would be nice to use such an actor/queue to post-back to the UI as well - right now I am using Android's support for posting an (asynchronous) Runnable to the UI thread.
I've briefly looked at several different actor implementations (mainly standard Scala and the Scalaz) and some different Java "message passing" libraries such as Jetlang, but most seem to use implicit threads or a thread executor service. But, in my case I wish to [run the actor and] process messages at a specific time on a specific thread. For View.sendMessage the messages should also be processed on the UI thread, but timing is not as important and can piggyback off of the Runnable execution noted above.
Then, I guess my question is, given the above:
What would be a good - as in "efficient" and idiomatic - approach to feed data between these two threads?
(I am also willing to entertain the suggestion that I completely fail to understand Scala actors and/or Scalaz actors and/or other message passing libraries; Scalaz seems like it might be able to work as I envision, but is hard for me to follow.)

Well, while I would still like to know of a generic/reusable approach to the above, practicality calls. This can also be done by running a Looper on the game thread and then putting the game "event loop stuff" inside the IdleHandler, but I did not like that inversion ..
Here is how I have currently implemented it:
Game/Thread class:
var handler: Handler = _ // handler created on View thread
// Send Message to Looper that exists on View thread
// (Created implicitly for all UI threads.)
def publishEvent(event: OutputEvent) {
handler.obtainMessage(0, event).sendToTarget
}
protected val queue = new ConcurrentLinkedQueue[InputEvent]
def queueEvent(event: InputEvent) { // on UI thread
queue.add(event)
}
def processQueuedEvents() { // on game Thread
#tailrec
def processNextEvent {
val event = queue.poll
if (event ne null) {
doStuffWithInputEvent(event)
processNextEvent
}
}
processNextEvent
}
override def run() { // on game Thread
while (running) {
processQueuedEvents
doOtherGameStuff ~ call_publishEvent ~ etc
}
}
View class:
// Created on UI thread, passed to Game instance
// (The Looper will dispatch Messages to Handlers.)
val handler = new Handler {
override def handleMessage(m: Message) {
val event = m.obj
doStuffWithOutputEvent(event)
}
}
// on UI thread
override def onTouch(v: View, ev: MotionEvent): Boolean = {
// safely queued, will be processed at the start of each game loop
game.queueEvent(InputEvent(..))
}

Related

Limiting the maximum number of coroutines that can run in a scope

I am translating our current application from Java to Kotlin and I came upon this problem.
The java implementation used to use threads to transfer data from the server.
It would create about 100 different threads that would request data, but from what I have seen no more than 4 would run at a time, the others would wait for a thread to finish before starting.
When translating it to Kotlin I used Coroutines
This creates a problem because apparently the server can't handle 100 requests actually being sent.
All coroutines are launched in the same scope , so it's something like this:
//this is a custom scope that launches on Dispatchers.IO + a job that I can use to cancel everything
transferScope.launch {
//loadData is a suspending function that returns true/false
val futures = mDownloadJobs.map{ async { it.loadData() } }
val responses = futures.awaitAll()
//check that everything in responses is true etc....
}
Is there a way to make the specific transferScope to allow only up to 5 coroutines at a time and then when one finishes let a different one run? (I do not care about the order)
If it can't be done through the scope, is there a different way this can be achieved?
Require each coroutine to acquire a Kotlin Semaphore permit from a total of 5 permits before making a request.
Something like this:
import kotlinx.coroutines.sync.Semaphore
val requestSemaphore = Semaphore(5)
val futures = mDownloadJobs.map {
async {
// Will limit number of concurrent requests to 5
requestSemaphore.withPermit {
it.loadData()
}
}
}
val responses = futures.awaitAll()
You can do something like this, group the requests into chunks of 4, launch coroutines to process them and wait till that group is finished before launching a new one.
requests.chunked(4).forEachIndexed { index, chunk ->
coroutineScope {
LOG("processing chunk $index")
chunk.forEach {
launch {
delay(100)
}
}
LOG("done processing $index")
}
}
I believe you should Channel and limit the creation of coroutine that you are creating.
val channel = Channel<Job>()
transferScope.launch {
mDownloadJobs.forEach { channel.send(it) }
channel.close() // don't forget to close the channel
}
coroutineScope {
val responses = mutableListOf<Any>()
repeat(5).map {
launch {
for (job in mDownloadJobsChannel) {
responses.add(jobs.loadData())
}
}
}
}
Parallelization in this case is 5 coroutines.
I did not test this code :D and I am sure there are cleaner ways to do this.
Dispatchers.IO claims to create a thread pool and restrict span out to that pool. It's docstring tells you how to change the pool size (a system property tho).

How to properly implement camera2 realtime frame processing using RxJava?

I'm making reactive wrapper over camera2, my goal is to get each frame and then pass to face recognition.
So, I created a wrapper method over setOnImageAvailableListener
fun createOnImageAvailableFlowable(imageReader: ImageReader, handler: Handler): Flowable<ImageReader> {
return Flowable.create({ subscriber ->
imageReader.setOnImageAvailableListener({
if (!subscriber.isCancelled)
subscriber.onNext(it)
}, handler)
subscriber.setCancellable {
imageReader.setOnImageAvailableListener(null, null)
}
}, BackpressureStrategy.LATEST)
}
Reactive chain looks as follows:
createOnImageAvailableFlowable(imageReader!!, null)
.concatMap {
it.acquireLatestImage()?.use { image ->
val rotation = ReactiveCamera.getRotationCompensation(cameraId!!, this, applicationContext)
val visionImage = FirebaseVisionImage.fromMediaImage(image, rotation)
firebaseFaceDetector
.detectInImage(visionImage)
.toFlowable(BackpressureStrategy.LATEST)
.map { list ->Optional(list)}
} ?: Flowable.just(Optional(null))
}
...
This code works, but cause some lags on preview surface because all work performed in the main thread. This needs to be performed in separate thread. My naive solution is to add observeOn operator before concatMap:
createOnImageAvailableFlowable(imageReader!!, null)
.observeOn(Schedulers.io()) // doesn't switch thread
.concatMap {
// still main thread
}
...
But it doesn't affect, all work still in the main thread. If I specify concatMapEager instead of concatMap, all works as expected in separate thread, but the frames comes with a significant delay.
What I'm doing wrong? How can I instruct the reactive stream to be performed in a separate thread in this case? How can backpressure be handled in case of realtime frame processing?
Upd
I provided my own thread as Kiskae suggested, but now, only first emission happens in scheduler's thread, but the rest emissions remain in the main thread:
createOnImageAvailableFlowable(imageReader!!, null)
.subscribeOn(AndroidSchedulers.from(nonMainThread.looper))
.concatMap {
val t = Thread.currentThread()
val name = t.name
Log.d(TAG, "current thread {$name}")
...
}
Output:
D/MainActivity: current thread {Camera2}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
D/MainActivity: current thread {main}
Looking at the documentation of ImageReader.setOnImageAvailableListener:
Handler: The handler on which the listener should be invoked, or null if the listener should be invoked on the calling thread's looper.
Since you're subscribing on the main looper it ends up setting up the callback using the main looper, this causes all the processing before the concatMap to always occur on the application thread.
You can solve this by either providing a handler instead of null or calling subscribeOn and providing a handler-based scheduler like RxAndroid's HandlerScheduler.

Refactor to fix architectural error

In a sort-of-working application I see this monstrous code:
class SomeUglyClass extends Thread {
ArrayList<SomeData> someDataStructure = new ArrayList<SomeData>();
Handler mHandler = new Handler() {
// a lot
// writing to someDataStructure
}
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
} // end of run(), total 500 lines of code
} // end of SomeUglyClass, total 4K lines of code
Maybe you already see the problems with this code. If not, here they are:
mHandler is attached to the UI thread (because it is created by the thread that loads the class, which is the main thread)
there's no looper (which is fact is the bug)
the thread wastes CPU time and drains the battery
someDataStructure is not thread-safe, but synchronizing elementary access operations will not help; synchronizing large blocks of code in a endless loop will likely block the guarded resource and make it unavailable for other threads; finally, it is not only someDataStructure, the whole class is based on the assumption that only one thread can run its code.
I cannot just add the looper, because the endless loop in run() has to be run, while Looper.loop(); also is an infinite loop. One thread cannot run two infinite loops.
Despite this epic architectural fail, the code is really doing something, it cannot be re-written at once, it is 4K lines of code, and often I can only guess what the code really does.
I need to refactor it. It should be a sequence of small steps preserving the functionality.
How do I refactor this terrific code?
You should try separation of concerns: try first to divide the whole class into many smallest one, each one responsible for doing/dealing with exactly one thing.
You may have something for data Access (read/write data), service (isolated business logic), and the UI. You may use event bus to decouple between objects (consider otto) and may be dependency injection (consider Dagger).
This process of separation will help you understand what each piece of code is doing and also the dependencies between the different parts, thus making writing unit/integration tests much easier.
Add lots of tests, use version control and then work as slowly as you need to.
The 1st step has been to change:
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
}
to:
#Override
public void run() {
Looper.prepare();
mHandler = new MyHandler();
mHandler.post(run_step);
Looper.loop();
}
Runnable run_step = new Runnable() {
int some_count, ...;
#Override
public void run()
{
//while(true) {
// a lot
// r/w access to someDataStructure
mIntoThreadHandler.postDelayed(this, 1);
//}
}
}
This preserves the functionality but still wastes CPU time. The urgent bug has been fixed, and the issue has been closed; I could not sell "must refactor to kill monstrous code" to my management, but I could sell "this can work faster if I refactor," so a new separate issue has been opened. UGH!
PS no chance to sell "lots of tests".

Task queue on Android like in GCD on iOS?

Is there such a thing as task queue on Android? I know that it can be written by hand but is there a ready to use library for that?
I'm not sure if there would be a library for this one, as Android already provides the high-level building blocks for what you're trying to achieve.
Handler
If I understood you correctly, you want to post tasks from any thread to be queued and executed one-by-one on a dedicated thread. This is very much what Android Handler is meant for.
Key traits of Handler, Looper and MessageQueue
A Handler is tied to a single Looper.
Each Looper has an associated MessageQueue
Handler uses a Looper underneath to enqueue and dequeue messages in a thread-safe manner into the Looper's MessageQueue.
Handler objects are inherently thread-safe and hence can be passed around to other threads safely.
You can have multiple Handler objects tied to a same Looper. This is useful if you want to process different kinds of messages using different Handlers. In this case, you are guaranteed that only one of the Handlers will process a Message/Runnable for a given Looper. The Looper takes care of dispatching the Message to the right Handler.
If you're already familiar with the Message Queue paradigm for communicating between 2 threads (or similar golang's buffered channel pattern), Handler is just a high level class which lets you use this pattern easily.
Example for using Handler to send/receive Messages, post Runnables
// BEGIN One-time Initialization
// Create a Handler thread
// This provides the looper for the Message Queue and
// will be processing all your messages (i.e. tasks).
handlerThread = new HandlerThread("SomeThreadName");
// Start the Handler Thread
// The thread will block (using the looper) until it
// receives a new message
handlerThread.start();
// Create a Message Handler which you can use to
// post and process messages
// The same Handler can also be used to post a Runnable which will get
// executed on handlerThread
handler = new CustomHandler(mHandlerThread.getLooper());
// END One-time Initialization
// Different ways to post a message to the Handler Thread
// These calls are thread-safe, can be called safely and
// concurrently from multiple threads without race conditions
handler.sendEmptyMessage(MESSAGE_ID_1);
handler.sendEmptyMessage(MESSAGE_ID_2);
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_3, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_4, value, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_5, value1, valu2, obj1));
// Post a runnable on the Handler Thread
// This is thread-safe as well
// In fact all methods on the Handler class are thread-safe
handler.post(new Runnable() {
#Override
public void run() {
// Code to run on the Handler thread
}
});
// A skeleton implementation for CustomHandler
// NOTE: You can use the Handler class as-is without sub-classing it, if you
// intend to post just Runnables and NOT any messages
public class CustomHandler extends Handler {
public CustomHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message message) {
if (message != null) {
// Process the message
// The result can be sent back to the caller using a callback
// or alternatively, the caller could have passed a Handler
// argument, which the Handler Thread can post a message to
switch (message.what) {
case MESSAGE_ID_1:
// Some logic here
break;
case MESSAGE_ID_2:
// Some logic here
break;
case MESSAGE_ID_3:
// Some logic here
break;
case MESSAGE_ID_4:
// Some logic here
break;
case MESSAGE_ID_5:
// Some logic here
break;
// Add more message types here as required
}
}
}
}
// After you're done processing all messages and you
// want to exit the Handler Thread
// This will ensure that the queue does not accept any
// new messages, and all enqueued messages do get processed
handlerThread.quitSafely();
Deviations from the above example
Although I've used HandlerThread in the above example, it is not mandatory to use it. You can even use the Looper calls directly, i.e. Looper.prepare() and Looper.loop() to run your own message loop in a thread.
As already mentioned in the comments, you do not need to sub-class the stock Handler if you do not intend to handle any messages.
You can communicate between multiple threads easily by using a Handler for each thread that needs to receive the message.
There are methods in Handler to schedule message delivery and Runnable execution in the future as well.
Android's framework internally uses Handler extensively for managing component lifecycle events (onPause, onResume, etc.).
AsyncTask
AsyncTask is another alternative to scheduling tasks on a different thread. . I won't go into too much detail of its implementation, as the Android developer documentation already describes it in detail.
I usually use AsyncTasks for tasks that I know I'll use a background thread for a long time (easily >= 100 ms at least). Some examples which fall into this category I can think of are Binder IPC, RPC calls, Network calls, Background downloads, etc.
On the other hand, Handler is more tailored for situations focussed on processing more number of messages as quickly as possible. In other words avoid performing any blocking operation in handleMessage(). You can write lock-free code easily using Handler, it manages all the locking for you when enqueuing and dequeuing messages.
In fact AsyncTask can be used in combination with Handler by splitting the work into a fast part (taken care by Handler) and a slow part (taken care by AsyncTask).
PS: Although tangential to the question, if you're interested in the Message Queue paradigm; do take a look at LMAX Disruptor, which is a high performance inter-thread Message Queue library. Their design document explains pretty well, which parts of the Message Queue, need locking/atomic access.
I've also looked around for something like GCD for Android. While Handlers and AsyncTasks are awesome the beauty of GCD (in my humble opinion) is that you can dispatch a workload on a background thread to do the heavy lifting. When the execution is done it i easy to execute the UI updates on the UI thread.
Since I did not find anything me and my school mate decided to create one of our own.
You can find it at:
ICDispatch on github
Basically all you need to do is to declare an Application class that extends ICDispatchApplication instead of Application and when you want to dispatch something you just call on
App.executeOn(int queue, ICBlock block);
Example:
App.executeOn(ICDispatch.NORMAL, new ICBlock(){
public void run(){
//do stuff...
App.executeOn(ICDispatch.MAIN, new ICBlock(){
public void run(){
//post result to UI thread.
}
}
}
});
The worst part is that there will be a lot of indentation. In order to minimize indentation you could use lambda notation:
App.executeOn(ICDispatch.NORMAL, ()->{
//do stuff...
//do some more...
//then even more
App.executeOn(ICDispatch.MAIN,() -> {
//Post result on UI thread.
}
});
At the moment ICDispatch supports LOW, NORMAL, HIGH, MAIN and CONCURRENT queueing. Features will be added as they are implemented.
I don't know iOS so I'm not sure if it is the same but in Android you have the ScheduledThreadPoolExecutor
For anyone finding this thread now, there is a new framework available called Bolts. It has tasks and continuations and can wait on multiple tasks to finish, like GCD.
I take this sample from Telegram Code :
You can declare extended thread for this approach
public static volatile DispatchQueue globalQueue = new DispatchQueue("globalQueue");
the class is :
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.util.concurrent.CountDownLatch;
public class DispatchQueue extends Thread {
private volatile Handler handler = null;
private CountDownLatch syncLatch = new CountDownLatch(1);
public DispatchQueue(final String threadName) {
setName(threadName);
start();
}
private void sendMessage(Message msg, int delay) {
try {
syncLatch.await();
if (delay <= 0) {
handler.sendMessage(msg);
} else {
handler.sendMessageDelayed(msg, delay);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void cancelRunnable(Runnable runnable) {
try {
syncLatch.await();
handler.removeCallbacks(runnable);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void postRunnable(Runnable runnable) {
postRunnable(runnable, 0);
}
public void postRunnable(Runnable runnable, long delay) {
try {
syncLatch.await();
if (delay <= 0) {
handler.post(runnable);
} else {
handler.postDelayed(runnable, delay);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
public void cleanupQueue() {
try {
syncLatch.await();
handler.removeCallbacksAndMessages(null);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
#Override
public void run() {
Looper.prepare();
handler = new Handler();
syncLatch.countDown();
Looper.loop();
}
}
and the Caller :
globalQueue.postRunnable(new Runnable() {
#Override
public void run() {
/* do here what you want */
}
});
You should check Handler & Loopers
Handlers, by default (*), like dispatch_get_main_queue() and you can post any block (Runnable instance) of code. Same approach also acquired with Context.runOnUiThread() and View.post(Runnable)
(*) Default constructor of Handler inherits the current thread's Looper instance (RunLoop in iOS) and queues (via handlerInstace.post...() methods) Runnable instances on Looper.
For more advance usage. You can create your own Looper instance (be aware it is a bit tricky :)). Still this might be handy...
Also for more advance usage, Handlers are the best tools i come across on Android (and yes, i miss them on iOS) for messaging inside application (inter-process communication something i guess). They might be customized to handle posted messages, bla, bla...

How to detect UI thread on Android?

Is there a robust way to detect if Thread.currentThread() is the Android system UI thread in an application?
I would like to put some asserts in my model code that asserts that only one thread (eg the ui thread) accesses my state, to assure that no kind of synchronization is necessary.
Common practice to determine the UI Thread's identity is via Looper#getMainLooper:
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
From API level 23 and up, there's a slightly more readable approach using new helper method isCurrentThread on the main looper:
if (Looper.getMainLooper().isCurrentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
I think that best way is this:
if (Looper.getMainLooper().equals(Looper.myLooper())) {
// UI thread
} else {
// Non UI thread
}
As of API level 23 the Looper has a nice helper method isCurrentThread. You could get the mainLooper and see if it's the one for the current thread this way:
Looper.getMainLooper().isCurrentThread()
It's practically the same as:
Looper.getMainLooper().getThread() == Thread.currentThread()
but it could be a bit more readable and easier to remember.
public boolean onUIThread() {
return Looper.getMainLooper().isCurrentThread();
}
But it requires API level 23
Besides checking looper, if you ever tried to logout thread id in onCreate(), you could find the UI thread(main thread) id always equals to 1. Therefore
if (Thread.currentThread().getId() == 1) {
// UI thread
}
else {
// other thread
}
Nice extension for Kotlin:
val Thread.isMain get() = Looper.getMainLooper().thread == Thread.currentThread()
So you just call:
Thread.currentThread().isMain
Couldn't you use the runOnUiThread method in the Activity class?See..
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Categories

Resources