1

在 C++ JNI 函数(包括在下面的半伪函数)中,至少在该client_ = new VClient(&callback_)行创建了一个(并且可能是两个)附加线程。我认为完成这个函数就足够了,但显然当下一个函数(另一个 JNICALL 函数)在此之后“立即”调用时,它会导致一个 SEGFUALT(“立即”在引号中,因为该函数被调用的速度很快有人可以按下下一个按钮)。我认为这是因为new VClient在 Init 函数返回并调用下一个函数时创建尚未完成,因为在下client_一个函数中使用了。

我对所有这些线程业务都很陌生,我不确定这是否是正确的思路。我习惯于顺序执行代码,因此当代码从该client_行继续移动时,那是因为该行的所有内容都已完成。代码是否可以从这一行继续,并在新VClient的完全创建之前从 JNI Init 函数返回?如果是这样,我如何让这个函数等到类/对象创建完成?

JNIEXPORT void JNICALL Java_com_ClassDir_Init(JNIEnv *env, jobject obj)
{
  LOGI("%s", __PRETTY_FUNCTION__);
  if(!client_)
  {
    LOGI("Initializing client");
    client_ = new VClient(&callback_);
    [Bunch of JNI/JAVA class and methodID lookup and saving]
  }
  else
    LOGI("Client already initialized");
}

*这callback_是一个处理向 JNI/JAVA 发送枚举类型信号以更新程序进度的类。

4

2 回答 2

1

你说VClient构造函数创建线程。创建线程是一个同步过程:在VClient线程完全创建并且很可能启动之前,ctor 的执行不会继续,因为我没有看到 VClient istance 上的任何其他方法调用来执行它。什么同步,就是这个开始的线程。这并不意味着“完全可操作”,只是您的主线程已指示创建的线程开始在自己的上下文中运行。当新线程的执行循环建立并进入时,是完全异步的(对于您的 VClient 构造)并且取决于线程调度。因此,如果您的“下一个 JNI 函数”试图调用该线程并在那里使用一些资源,则该资源必须已经可用(这意味着您希望新线程已经进展到使其可用)并且可以访问必须保护该资源以进行线程安全访问。

所以你需要在这个线程业务中变得不那么新鲜 :-) 查找两个基本构建块:

  1. 等待条件(也称为“阻塞条件变量”)。调用 VClient ctor 后,您将等待需要传递给线程的对象。线程将在完成其基本工作时通知条件,从而解除第一个线程中的等待。
  2. 互斥体。每当有一个资源(数据结构)可以通过执行多个线程并发访问时,您需要在访问代码之前锁定互斥锁,然后再解锁。稍后到达的线程将在锁上阻塞,直到第一个线程完成。否则当两个线程试图修改同一个内存时,你会得到奇怪的结果或直接崩溃。

这些在每个操作系统和每个框架的各种 API 中实现不同。甚至同一操作系统上的不同框架也往往不同。但哲学是平等的。

顺便说一句,我理所当然地认为,当“下一个 JNI 函数”尝试使用它client_时,它不会超出范围。这可能意味着 JNI 实现中的全局变量——我没有看到本地代码的任何类包装器。

于 2012-09-20T10:03:40.963 回答
0

不。调用“new VClient()”的代码行不会继续到下一行,直到 VClient 构造函数退出。执行是顺序的。你的问题在别处。

于 2012-09-19T23:17:15.500 回答