【问题标题】:NDK c++ std::thread abort crash on joinNDK c++ std::thread abort crash on join
【发布时间】:2017-02-06 11:29:15
【问题描述】:

首先,我没有先验的 C 知识。我正在尝试整理一个线程。这是我的例子。我先调用start,然后在java端做了一些工作后我调用stop

#include <jni.h>
#include <thread>
std::thread LOOPING_THREAD;
bool do_job = false;

//looping func
 void looping(int test) {
   while (do_job) {
    LOGD("Doing job");
   }
}

//start
JNIEXPORT jint JNICALL
Java_com_example_start(JNIEnv *env, jobject thiz,) {
LOOPING_THREAD = std::thread(looping, 1);
}

JNIEXPORT jint JNICALL
Java_com_example_stop(JNIEnv *env, jobject thiz) {
do_job= false;
LOOPING_THREAD.join();
return 0;
  }

  }

以上通常工作正常,但虽然我无法自己重现它,但我在调用后得到关于中止线程的本机崩溃日志

LOOPING_THREAD = std::thread(looping, 1);

例如

#00 pc 00044340  /system/lib/libc.so (tgkill+12)
#01 pc 00041f41  /system/lib/libc.so (pthread_kill+32)
#02 pc 0001ba6f  /system/lib/libc.so (raise+10)
#03 pc 00018c11  /system/lib/libc.so (__libc_android_abort+34)
#04 pc 000167d0  /system/lib/libc.so (abort+4)
#05 pc 00010aa3  /data/app/com.app-1/lib/arm/libapp.so    (_ZN9__gnu_cxx27__verbose_terminate_handlerEv+230)
#06 pc 0000cfb9  /data/app/com.app-1/lib/arm/libapp.so (_ZN10__cxxabiv111__terminateEPFvvE+4)
#07 pc 0000d0c1  /data/app/com.app-1/lib/arm/libapp.so (_ZSt9terminatev+8)
#08 pc 00008ddb  /data/app/com.app-1/lib/arm/libapp.so (_ZNSt6threadaSEOS_+38)

如何防止这种崩溃?我尝试添加互斥锁和解锁以按如下方式运行和停止,但它会导致循环在完成之前挂起一段时间,这在这种情况下是不可接受的。

 void looping(int test) {
    while (do_job) {
      mutex.lock()
     LOGD("Doing job");
     mutex.unlock()
  }

 JNIEXPORT jint JNICALL
  Java_com_example_stop(JNIEnv *env, jobject thiz) {
   mutex.lock()
   do_job= false;
   mutex.unlock()
   return 0;
 }

更新

我已经删除了锁,而是在创建线程并让它运行之后,在 JNI start(..) 处使用 detach() 分离线程。然后,在设置 do_job = true 后在 JNI stop(...) 处等待 200 毫秒

这行得通吗?

【问题讨论】:

  • 请在您的示例中修复代码缩进。

标签: android c++ multithreading c++11 android-ndk


【解决方案1】:

_ZNSt6threadaSEOS_std::thread::operator=(std::thread&amp;&amp;)。您可以使用c++filt 实用程序来对符号名称进行分解。

来自 std::thread::operator= 的文档

如果 *this 仍有关联的运行线程(即 joinable() == true),调用 std::terminate()。否则,将 other 的状态分配给 *this 并将 other 设置为默认构造状态。

所以您的全局变量LOOPING_THREAD 包含尚未完成的活动线程。

【讨论】:

  • 谢谢。那么,将其转换为局部变量并在创建它后调用 detach() 修复它吗?像 std::thread LOOPING_THREAD = std::thread(looping, 1); 一样内联它LOOPING_THREAD.detach();
  • 如果您致电detach,您将无法加入该主题。您还失去了在进程关闭时正确终止线程的能力。分离线程不会解决拥有线程使用的数据的任何问题。因此,分离线程将解决这个特定问题,但如果你这样做,你很可能会遇到许多其他问题。最好在程序中细化拥有关系,并且
  • 该线程中调用的函数是一个非常简单的while循环,运行n次或满足条件后退出。我知道一旦存在循环,线程也会退出,因此不需要加入?对吗?
  • 不,不正确。您将遇到程序终止问题,您将遇到停止条件问题(它仍然是一个全局变量并将控制所有线程)。并且,可能还有其他与对象生命周期有关的问题。
  • 我没有 C 知识,有什么可以学习的示例吗?启动后我无法加入线程。它必须运行并等待另一个命令完成。
猜你喜欢
  • 1970-01-01
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多