2023-01-21 278
问题简介
我通过JNI在一个过程中使用C ++和Java.对于有问题的用例,C ++线程和Java线程都在访问相同的数据,它们在C ++方面都这样做,我想正确同步访问.
到目前为止,我几乎所有的JNI线程同步都位于Java侧,答案很明显:使用提供的Java并发软件包和内置的并发语言功能.不幸的是,答案在C ++方面并不那么明显.
我到目前为止尝试过的简短
我尝试使用pthreads mutex以为即使我不使用pthreads来创建线程,它也可能起作用,但是当试图锁定时偶尔会卡住 – 我会显示下面的一个示例.
在我当前的特定用法中,C ++正在对Java在1秒的计时器上提供的更改进行轮询(不是我想要的,但我不确定如何将其作为事件驱动传统C ++代码). Java线程通过调用本机函数来提供数据,C ++将数据复制为C ++结构.
这是代码中的情况类型(发生在2个线程,thread1和thread2):
代码示例
注意一个SSCCE,因为它缺少TheData和TheDataWrapper的定义,但这并不重要.假设它们仅包含几个公共int,如果这有助于您的思考过程(尽管在我的情况下,它实际上是int和float的多个阵列).
c ++:
class objectA
{
void poll();
void supplyData(JNIEnv* jni, jobject jthis, jobject data);
TheDataWrapper cpp_data;
bool isUpdated;
void doStuff(TheDataWrapper* data);
};
// poll() happens on a c++ thread we will call Thread1
void objectA :: poll()
{
// Here, both isUpdated and cpp_data need synchronization
if(isUpdated)
{
do_stuff(&cpp_data);
isUpdated = false;
}
}
// supplyData happens on the Thread2, called as a native function from a java thread
void objectA :: supplyData(JNIEnv* jni, jobject jthis, jobject data)
{
// some operation happens that copies the java data into a c++ equivalent
// in my specific case this happens to be copying ints/floats from java arrays to c++ arrays
// this needs to be synchronized
cpp_data.copyFrom(data);
isUpdated = true;
}
java:
class ObjectB
{
// f() happens on a Java thread which we will call Thread2
public void f()
{
// for the general case it doesn't really matter what the data is
TheData data = TheData.prepareData();
supplyData(data);
}
public native void supplyData(TheData data);
}
当我尝试按照下面的pthread锁定时,有时执行会卡在pthread_mutex_lock中.在这种情况下,不应该发生僵局,但要进一步测试,我遇到了一个根本没有被调用的场景(没有提供数据),因此不可能进行僵局,但是第一个呼吁poll偶尔会悬挂.在这种情况下,也许使用pthreads mutex并不是一个好主意?也许我做了一些愚蠢的事情,并不断忽视它.
到目前为止,我尝试使用以下pthreads:
代码示例
c ++:
class objectA
{
pthread_mutex_t dataMutex;
... // everything else mentioned before
}
// called on c++ thread
void objectA :: poll()
{
pthread_mutex_lock(&dataMutex);
... // all the poll stuff from before
pthread_mutex_unlock(&dataMutex);
}
// called on java thread
void objectA :: supplyData(JNIEnv* jni, jobject jthis, jobject data)
{
pthread_mutex_lock(&dataMutex);
... // all the supplyData stuff from before
pthread_mutex_unlock(&dataMutex);
}
我想到但没有做过的另一种选择
我还考虑使用JNI回到Java中,以使用Java的并发控制请求锁.这应该起作用,因为任何一个线程都应根据需要阻止Java侧.但是,由于从C ++访问Java的冗长过于冗长,因此我希望避免遇到这种头痛.我可能可以做一个C ++类,将JNI调用封装到Java中以请求Java锁.这将简化C ++代码,尽管我想知道仅用于线锁的JNI来回交叉的开销.
根据@radiodef的评论,似乎没有必要. JNI似乎包括MonitorEnter/MonitorExit功能,该功能已经处理了C ++侧的锁定.与Java侧的常规锁一起使用时,有很多陷阱,因此请在此处阅读.我将尝试一下,我希望MonitorEnter/MonitorExit将是答案,我建议@radiodef从评论中做出答案.
我如何正确同步? pthread_mutex_(un)锁定吗?如果没有,我可以用什么来在C ++线程和Java线程之间同步?
由于JNI桥在工作,因此我可以来回传递数据,因此在这里没有提供JNI特定的C ++代码.这个问题是关于否则正确通信的C ++/Java线程之间的正确同步.
如前所述,我希望避免进行投票方案,但这可能最终成为另一个问题.旧版C ++代码以X/图案显示其用户界面的一部分,如果我没记错的话,上面的C ++线程恰好是用于显示的事件线程.一旦插入了此类的Java用户界面,Java事件Dispatch线程最终将成为Java事件Dispatch线程,尽管现在Java线程是自动化的测试线程.无论哪种方式,这是一个单独的Java线程.
C ++线程连接到JVM.实际上,这是创建JVM的C ++线程,因此默认情况下应附加.
我已经成功地将其他Java用户界面元素插入此程序,但这是C ++首次需要从Java中进行非原子数据,这需要同步.是否有一种公认的正确方法来执行此操作?
如果两个线程都连接到JVM,则可以通过MonitorEnter(jobject)’s MonitorEnter(jobject)和MonitorExit(jobject)函数访问JNI的同步.就像听起来一样,MonitorEnter aquiriagir在提供的jobject上锁定,MonitorExit释放了提供的jobject上的锁.
注意:有一些陷阱要注意!请注意MonitorEnter的描述的第二到最后一段以及MonitorExit的最后一段关于混合和匹配MonitorEnter/MonitorExit与其他类似机制的描述,您可能会认为这些机制是兼容的.
请参阅在这里
Monitorenter
Jint Monitorenter(Jnienv *env,jobignt obj);
输入与基础Java对象相关的显示器
由OBJ.输入与所指对象关联的监视器
由OBJ. OBJ参考不得无效.每个Java对象都有一个
与之关联的监视器.如果当前线程已经拥有
与OBJ关联的监视器,它会增加监视器中的计数器
指示该线程输入监视器的次数.如果
与OBJ关联的监视器不属于任何线程,
当前线程成为监视器的所有者,设置条目
该监视器的计数为1.如果另一个线程已经拥有监视器
与OBJ关联,当前线程等待直到监视器为
发布,然后再次尝试获得所有权.通过Monitorenter JNI函数调用输入的监视器不能为
使用monitorexit Java虚拟机指令或
同步方法返回. Monitorenter JNI功能调用和A
Monitorenter Java虚拟机指令可能会参加
与同一对象关联的监视器.为避免僵局,监视器通过Monitorenter JNI输入
必须使用monitorexit jni调用退出函数调用,除非
dixacrentThread调用用于隐式发布JNI
监视器.链接:
jnienv接口函数表中的索引217.
参数:
env:JNI接口指针.
obj:普通的java对象或类对象.
返回:
成功返回” 0″;返回失败的负值.
和
monitorexit
jint monitorexit(jnienv *env,jobject obj);
当前线程必须是关联的监视器的所有者
OBJ提到的基础Java对象.线程减小
表示输入此的次数的计数器
监视器.如果计数器的值变为零,则当前线程
释放监视器.本机代码不得使用monitorexit退出通过
同步方法或监视器Java虚拟机
指示.链接:
jnienv接口函数表中的索引218.
参数:
env:JNI接口指针.
obj:普通的java对象或类对象.
返回:
成功返回” 0″;返回失败的负值.
例外:
IllegalMonitorStateException:如果当前线程不拥有
监视器.
因此,应如下更改试图使用Pthreads的问题中的C ++代码(代码假设JNIEnv*指针以典型的JNI方式以某种方式获取了以某种方式获取):
class objectA
{
jobject dataMutex;
... // everything else mentioned before
}
// called on c++ thread
void objectA :: poll()
{
// You will need to aquire jniEnv pointer somehow just as usual for JNI
jniEnv->MonitorEnter(dataMutex);
... // all the poll stuff from before
jniEnv->MonitorExit(dataMutex);
}
// called on java thread
void objectA :: supplyData(JNIEnv* jni, jobject jthis, jobject data)
{
// You will need to aquire jniEnv pointer somehow just as usual for JNI
jniEnv->MonitorEnter(dataMutex);
... // all the supplyData stuff from before
jniEnv->MonitorExit(dataMutex);
}
@radiodef提供了答案.不幸的是,这是评论.我等到第二天下午,让Radiodef有时间做出答案,所以现在我要这样做了.谢谢Radiodef提供了我需要修复的轻推.
如果您在本机线程和Java线程之间进行同步,则使用本机静音和Java监视器可能是谨慎的.
另外,如果您有可用的话,我建议使用std :: mutex在本机线程中建立同步. std :: lock_guard也很有用,并且为具有.lock()和.unlock()方法的Java监视器创建一些包装器,因此您可以使用std :: lock_guard使用它们也会有所帮助(那么您可以让C ++让C ++编译器完成工作).
我说您应该使用两者的主要原因是因为Monitorenter并不完美,它容易竞争条件.具体而言,据我从JNI文档中所知,它无法建立同步( jni文档).
本机STD :: mutex.lock()的使用将同步与本机解锁.
#include <mutex>
jobject magicObtainLockObject();
JNIEnv* magicObtainJNIEnv();
struct compound_lock{
private:
std::mutex mtx;
public:
void lock(){
mtx.lock();
magicObtainJNIEnv()->MonitorEnter(magicObtainLockObject());
}
void unlock(){
magicObtainJNIEnv()->MonitorExit(magicObtainLockObject());
mtx.unlock();
}
};
struct objectA{
...
compound_lock lock;
};
void objectA::poll(){
std::lock_guard<compound_lock> sync{lock};
...
}
void objectA::supplyData(JNIEnv* jni, jobject jthis, jobject data){
std::lock_guard<compound_lock> sync{lock};
...
}
以上所述是小编给大家介绍的您如何在JNI环境的本机侧正确同步线程?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/26271.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态