多线程程序中JPL库的意外行为(连接Java和Prolog)
我一直在试验JPL的多线程特性。据我从源代码中的注释中了解,每个Java线程分配一个不同的Prolog引擎。 显然,当在线程a中启动一个查询,在线程a生成的线程B中执行另一个查询,并且在线程a中再次执行第三个查询时,就会出现问题 以下代码片段说明了该问题:多线程程序中JPL库的意外行为(连接Java和Prolog),java,multithreading,prolog,jpl,Java,Multithreading,Prolog,Jpl,我一直在试验JPL的多线程特性。据我从源代码中的注释中了解,每个Java线程分配一个不同的Prolog引擎。 显然,当在线程a中启动一个查询,在线程a生成的线程B中执行另一个查询,并且在线程a中再次执行第三个查询时,就会出现问题 以下代码片段说明了该问题: public static void main(String[] args) { try { ... Query query; query = new Query("true");
public static void main(String[] args) {
try {
...
Query query;
query = new Query("true");
System.out.println(query.hasSolution()); //succeeds
Thread t = new Thread() {
@Override
public void run() {
Query query2 = new Query("true");
System.out.println(query2.hasSolution()); //succeeds
}
};
t.start();
t.join();
query = new Query("true");
System.out.println(query.hasSolution()); //fatal error
} catch (Exception e) {
throw new RuntimeException(e);
}
}
由于JPL文档提到不能同时激活两个查询,因此代码会等到线程完成后再继续执行最后一个查询。我还不清楚该约束是否仅适用于同一线程中的查询,或者是否适用于不同线程和引擎中的查询
在前面的示例中,只有前两个查询成功。当执行第三个查询时,我获得以下致命错误:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x000000010db65bd5, pid=79191, tid=7171
#
# JRE version: 7.0_06-b24
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.2-b09 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C [libYap.dylib+0x125bd5] PL_open_foreign_frame+0x45
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
...
这是JPL中的一个bug吗?在这种情况下,是否有人知道如何将JPL与多线程结合使用
我使用YAP版本6.2.2和6.3.2进行了测试,结果相同
更新:
正如@sharky所建议的,显然这是YAP二进制文件或YAP的JPL端口的问题。使用SWI时,问题中显示的示例运行良好
我仍然对多线程程序中的JPL行为感到困惑。
查看JPL库中查询类中open方法的源代码和注释:
public synchronized final void open() {
...
if (Prolog.thread_self() == -1) { // this Java thread has no attached Prolog engine?
engine = Prolog.attach_pool_engine(); // may block for a while, or fail
} else { // this Java thread has an attached engine
engine = Prolog.current_engine();
}
...
}
似乎是说JPL将为每个线程创建一个新的逻辑引擎。
但是,如果我执行这个简单的程序:
Thread t = new Thread() {
@Override
public void run() {
Query query = new Query("assert(x)");
query.hasSolution()
query = new Query("x");
System.out.println("Thread1 x:" + query.hasSolution()); //query succeeds
}
};
t.start();
t.join();
t = new Thread() {
@Override
public void run() {
Query query = new Query("x");
System.out.println("Thread2 x:" + query.hasSolution()); //query also succeeds
}
};
t.start();
t.join();
我可以看到以下输出:
Thread1 x:true
Thread2 x:true
显然,第二个线程访问的Prolog引擎与第一个线程访问的Prolog引擎相同,而不像源代码及其注释所显示的那样是新的
如果有人有JPL和多线程的经验,请澄清这一点。现在我已经找到了可能的解决方案,但是仍然有一种方法可以访问定义的子句 你可以使用模块!序言文件:
:-module(thread1,[]).
x.
然后在thread1中,您可以询问thread1:x,它将成功
thread2将启动一个异常,您可以捕获它并说失败。。。除非你没有定义x动态
另一种方法是使用线程\本地。。。但是您必须将每个子句定义为thread\u local无聊 这是一个问题还是JPL的错误报告?嗨@Daniel,刚才在末尾添加了一行,澄清了这个问题。您是否尝试使用SWI作为后端,看看问题是否存在于YAP二进制文件中?嗨@sharky,是的,问题似乎正如您所建议的那样存在于YAP二进制文件中,因为SWI没有致命错误。在第一个例子中,第一个和第三个查询在同一个线程上。理论上,这应该是可以的,因为第一个查询在第三个查询执行之前完成。我猜在一个单独线程上的第二个查询可能与问题无关。如果删除第二个查询,然后在主线程上一个接一个地运行两个查询,是否会发生错误?另外,API文档提到在使用查询后应该关闭查询。那很可能会解决你的问题。