【问题标题】:How to kill a child thread in C (Android NDK)?如何在 C (Android NDK) 中杀死一个子线程?
【发布时间】:2014-07-22 15:29:29
【问题描述】:

在你告诉我不应该杀死线程而是发送一个信号/设置一个标志让它们做出反应之前,让我解释一下场景:

我正在使用 OpenSL API(播放本地 mp3 文件)在 Android NDK 中开发音频播放器,但 Android 实现有一个错误,如果我对文件重复执行查找操作,线程不幸挂起当我尝试释放资源时出现内部死锁(SLObjectItf->Destroy)。

所以我将销毁例程移至子线程并等待固定的时间使其完成,如果没有,我认为线程已挂起并继续执行泄漏一些资源,这比拥有更好转到系统设置并手动终止应用程序。

我尝试使用信号 SIGTERM 和 SIGKILL 通过 pthread_kill 终止子线程,但似乎两者都在终止我的整个应用程序并且 Android 重新启动它。我无法使用 pthread_cancel,因为线程已挂起,而且 Android NDK 不支持该方法。

有什么方法可以在不杀死整个应用的情况下杀死子线程?

编辑:这是线程和启动它的代码

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

【问题讨论】:

  • 你能发布一些代码吗?也许是 start_routine?
  • pthread_kill(destroyDecoderThread, SIGTERM); 它应该只杀死你提到的线程!

标签: android c multithreading android-ndk


【解决方案1】:

来自pthread_kill 手册页:

信号处置是进程范围的:如果信号处理程序是 安装后,处理程序将在线程 thread 中调用,但如果 信号的处置是“停止”、“继续”或“终止”, 这个动作会影响整个过程。

在 Dalvik 中,用于特殊处理的信号(例如 SIGQUIT 转储堆栈,SIGUSR1 导致 GC)在创建任何线程之前被阻塞,然后在 SignalCatcher 线程中使用 sigwait() 解除阻塞。您无法更改不受您控制的线程的阻塞状态,因此这对您不起作用。

您可以做的是为其他未使用的信号安装一个信号处理程序(例如,我不认为 SIGUSR2 被提供的 Dalvik 版本使用),并让它调用 pthread_exit()。如该功能的手册页所述:

当一个线程终止时,进程共享的资源(例如,互斥锁、 条件变量、信号量和文件描述符)不是 释放,并且使用 atexit(3) 注册的函数不会被调用。

这听起来像是“期望的”行为。

说了这么多,请不要放弃不这样做的希望。 :-) 听起来您认识到部分问题(资源泄漏),但您还必须考虑状态不一致的可能性,例如认为它们被退出的线程持有的互斥锁。您最终可能会处于其他线程现在挂起或行为异常的状态。

【讨论】:

  • 谢谢,它为 SIGUSR2 注册了一个信号处理程序,如果 SIGUSR1 也被 Android “占用”,这就解释了为什么我尝试它时它没有工作。
  • 你能分享一下你是如何注册信号处理程序的吗?
  • 为其他未使用的信号安装一个信号处理程序(例如,我不认为 SIGUSR2 被 Dalvik 的交付版本使用),并让它调用 pthread_exit() Ooof。不要永远那样做。 From within a signal handler, you can safely make calls to async-signal-safe functions only。从信号处理程序中调用诸如pthread_exit() 之类的函数会调用未定义的行为。想象一下,如果 Dalvik VM 在创建新线程的过程中被中断会发生什么......
  • @AndrewHenle:以这种方式终止线程是一个糟糕的主意,无论您是否从信号处理程序中执行它。异步信号安全是灾难圣代的重中之重。我的目标是解释信号处理行为,而不是推荐这种方法作为解决方案(作者似乎认为这是有缺陷的)。正确的解决方案是修复 OpenSL 挂起,但像这样的糟糕 hack 可以让您在某个部分取得进展,同时对另一部分进行修复。
  • 这是一个很好的答案,SIGQUIT 不起作用,但 SIGUSR1 确实有效!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-22
  • 2017-11-11
  • 1970-01-01
  • 2012-05-25
  • 2011-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多