2012-09-19 17 views
1

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

我对所有这些线程业务都比较陌生,我不确定这是否是一个正确的思路。我习惯于按顺序执行代码,因此当代码从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到节目进度更新类。

+0

可以显示堆栈跟踪(可能位于'hs_err *'文件中)吗?你如何保存Java类?你将它们转换为全局引用吗? VClient的构造函数是否保存任何Java引用?在哪个线程中调用了'callback'?你在VClient的构造函数中使用了哪些线程(你是否使用JNI调用)? – ninjalj

回答

1

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

所以,你需要成为这个线程业务少新:-)看看两个重要基石:

  1. 等待条件(又称“堵条件变量”)。在调用VClient ctor之后,您将等待一个您需要传入线程的对象。线程会在完成基本工作时通知条件,从而解除第一个线程中的等待状态。
  2. 互斥体。只要有一个资源(数据结构)可以通过执行多个线程同时访问,就需要在访问代码之前锁定该互斥锁,然后解锁。后来到达的线程会阻塞锁,直到第一个线程结束。否则,当两个线程尝试修改相同的内存时,您会得到奇怪的结果或直接崩溃。

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

顺便说一句,我想当然地认为client_以这样的方式,它不超出范围时“未来JNI功能”尝试使用它宣布。这可能意味着JNI实现中的全局变量 - 我没有看到任何本地代码的类包装。

+0

感谢您的信息。我们能够以这样的方式编写程序的Android UI/Java端,以至于这样的用户不能够快速地进行下一个JNI调用以导致段错误。但是,这些信息对于程序的其他部分来说非常方便。对于您提到的两个构建模块,您是否有任何关于良好资源的建议?再次感谢。 – AeroBuffalo

+0

我没有自己的终极资源,因为我通过实践和许多失败逐步学习了多线程编程。只是谷歌“线程介绍”。与往常一样,您可以从维基百科开始。 –

0

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