Before you tell me that I should not kill threads and instead send a signal/set a flag for them to react, let me explain the scenario:
I'm developing an audio player in Android NDK with OpenSL API (play a local mp3 file), but the Android implementation has a bug where If I perform repeatedly a seek operation on the file, the thread sadly hangs in a kind of internal deadlock when I try to free resources (SLObjectItf->Destroy).
So I moved the destroy routine to a child thread and wait for a fixed amount of time for it to finish, if it doesn't, I consider the thread as hanged and continue execution leaking some resources, which is preferable than having to go to the system settings and manually kill the app.
I tried to kill the child thread with pthread_kill using the signals SIGTERM and SIGKILL, but it seems both are terminating my whole application and Android restarts it. I cannot use pthread_cancel because the thread is hanged and also that method is not supported on Android NDK.
Is there any way to kill the child thread without killing the entire app?
EDIT: Here is the thread and the code starting it
static void *destroyDecoderInBackground(void *ignoredArgument)
{
if (decoderObject != NULL)
{
__android_log_print(ANDROID_LOG_INFO, "OpenSLES", "Destroying decoder object");
(*decoderObject)->Destroy(decoderObject);
__android_log_print(ANDROID_LOG_INFO, "OpenSLES", "Decoder object destroyed");
decoderObject = NULL;
decoderPlay = NULL;
decoderSeek = NULL;
decoderBufferQueue = NULL;
}
pthread_mutex_lock(&destroyDecoderLock);
pthread_cond_signal(&destroyDecoderCond);
pthread_mutex_unlock(&destroyDecoderLock);
pthread_exit(0);
}
static void destroyDecoder(JNIEnv* env)
{
logJava("Trying to destroy decoder");
struct timespec timeToWait;
struct timeval now;
// get absolute future time to wait
clock_gettime(CLOCK_REALTIME, &timeToWait);
timeToWait.tv_nsec = timeToWait.tv_nsec + (500 * 1000000);
// wait for destroy decoder thread to complete
pthread_mutex_lock(&destroyDecoderLock);
pthread_create(&destroyDecoderThread, NULL, &destroyDecoderInBackground, NULL);
logJava("Starting waiting");
pthread_cond_timedwait(&destroyDecoderCond, &destroyDecoderLock, &timeToWait);
pthread_mutex_unlock(&destroyDecoderLock);
logJava("Finished waiting");
if(decoderObject != NULL)
{
logJava("Destroy decoder hanged, killing thread, resources will leak!!!");
pthread_kill(destroyDecoderThread, SIGTERM);
decoderObject = NULL;
decoderPlay = NULL;
decoderSeek = NULL;
decoderBufferQueue = NULL;
}
}
From the pthread_kill man page:
Signal dispositions are process-wide: if a signal handler is installed, the handler will be invoked in the thread thread, but if the disposition of the signal is "stop", "continue", or "terminate", this action will affect the whole process.
In Dalvik the signals used for special handling (e.g SIGQUIT dumps the stacks, SIGUSR1 causes a GC) are blocked before any threads are created, and then unblocked in the SignalCatcher thread using sigwait(). You can't alter the block status for the threads you don't control, so this won't work for you.
What you can do instead is install a signal handler for an otherwise unused signal (e.g. I don't think SIGUSR2 is used by shipping versions of Dalvik), and have it call pthread_exit(). As noted in the man page for that function:
When a thread terminates, process-shared resources (e.g., mutexes, condition variables, semaphores, and file descriptors) are not released, and functions registered using atexit(3) are not called.
This sounds like the "desired" behavior.
Having said all that, please don't give up on the hope of not doing this. :-) It sounds like you recognize part of the problem (resource leaks), but you also have to consider the possibility of inconsistent state, e.g. mutexes that think they're held by the thread that exited. You can end up in a state where other threads will now hang or act strangely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With