Re: Suspend worker thread when in background
Eric Wing <[email protected]> Fri, 20 Jan 2017 17:54:03 -0800
| Newsgroups | gmane.comp.lib.sdl |
|---|---|
| Message-ID | <CA+Q62MAUDRPDpEst162YYL-E_gL7nGPs2D9=Eg6q3XKtOcyruQ@mail.gmail.com> |
On 1/20/17, rtrussell <[email protected]> wrote: > > Daniel Gibson wrote: >> Is there a way to tell Android to wait a little with either "paging out" >> the memory or even with switching to another app? >> Otherwise I have no idea, but maybe someone who (unlike me) has actual >> experience with Android can help > > Like you my knowledge of Android is very limited, and to a large extent I'm > relying on the SDL docs to tell me what to do (not entirely unreasonable I > think - it is supposed to be an 'abstraction layer' that isolates the > programmer from platform-specific detail!). > > What surprises me is that this seems to be an issue that has not been widely > encountered before. I would have expected worker threads to be the norm > these days - it's effectively the only way to achieve a short latency even > if the UI thread is waiting for VSYNC, and to leverage the power of > multi-core CPUs. > > Richard. > Android, and particularly the Android NDK, is awful. You can find many, many, people attest to this, including John Carmack. I give talks from time to time on Android development and always remember to call out how bad the NDK is, and I always get NDK developers thanking me at the end of the talk for publicly saying what we all know. So you are entering a rite of passage. - To your original problem of suspending the thread: I say don’t suspend your threads and just make them end. Design your threads so you tell them to quit and you do a wait/join. Then when your app resumes, start up new threads. - I would have expected worker threads to be the norm these days Threads + cross-platform has always been hard. So this does temper devs to some degree. SDL’s thread library tries to point you in the right direction by having a very small set of functions. For example, there is no SDL_SuspendThread because it is not ubiquitous. (As you discovered, Android doesn’t want to support it.) But unfortunately, it does not absolve you from understanding things about the platforms. Threads are among the worst because there are so many subtle differences and they really leak serious abstraction details. For example, Emscripten/web browser does not support threads at all (ignore web workers). And as far as leaky abstractions, one of the most common pitfalls is many platforms can’t handle doing certain operations on the non-main thread, so everybody using threads needs to be very careful about this. - app events race condition: Unfortunately, this is a consequence of threads/leaky abstraction details, and Android just being terrible. The fundamental problem is that on Android, SDL is actually running on a background thread. So when an app suspends, backgrounds, resumes, quits, etc., the events are happening on the main Android thread, and not the SDL thread. Android expects you to handle them NOW! But since SDL is on a background thread, there is a potential race condition. I have worked on many open source and commercial Android projects, and every one of them made the same mistake and put their stuff on a background thread. It didn’t help that Google itself encouraged developers to do this with their Native Activity example. I have compared notes with a lot of other Android devs who have to push the envelope on the NDK too, and we all came to the same conclusion that Native Activity/background thread is a terrible idea. Every single project I’ve been on has had some hard edge case race condition with suspend, background, resume, or quit. I’d actually like to write a new alternative SDLActivity some day that keeps SDL on the main thread. This would require some changes on how people deal with the event loop, but SDL actually already has to do this for Emscripten, and also has a special function to enable this mode on iOS, so it actually isn’t unprecedented. But that aside, I thought SDL will quit correctly on Android with respect to threads because it basically wait/joins the SDL background thread to end it, blocking the app on the main thread from quitting until this happens. (Threads are tricky so maybe there is an edge case I’m not seeing.) The bug that I usually see about quitting is due to a very different stupid, “NDK is terrible”, design problem. Android actually doesn’t necessarily clean up your NDK side memory. It just leaves it there untouched. So if you have global or static variables, when you restart the app, the Android system actually skips re-initializing all your global and static variables because it considers them already initialized. So these variables remain at their previous value which can completely break your application logic. int g_isRunning = 1; int main(int arcg, char* argv[]) { SDL_Init(SDL_VIDEO); // standard SDL event loop while(g_isRunning) { // handle the event loop which will set the g_isRunning to 0 if the user quits } SDL_Quit(); return 0; } The first time you launch this, it will work. Then quit the app. Then restart the app. g_isRunning will still be 0 from the last run because Android skips re-initializing the variable to 1. Basically, this forces you to be very careful, and always explicitly reinitialize your globals and statics. int g_isRunning = 1; int main(int arcg, char* argv[]) { // forces reinitialization for subsequent starts g_isRunning = 1; SDL_Init(SDL_INIT_VIDEO); // standard SDL event loop while(g_isRunning) { // handle the event loop which will set the g_isRunning to 0 if the user quits } SDL_Quit(); return 0; } -Eric _______________________________________________ SDL mailing list [email protected] http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org