【发布时间】:2023-04-09 06:49:01
【问题描述】:
我一直在试验 JPL 的多线程特性。据我从源代码中的 cmets 了解,每个 Java 线程分配了一个不同的 Prolog 引擎。 显然,当在线程 A 中启动一个查询,在线程 B 中执行另一个查询(由线程 A 生成),然后在线程 A 中再次执行第三个查询时,就会出现问题。
下面的sn-p代码说明了这个问题:
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 中的错误吗?在那种情况下,有人知道将 JPL 与多线程一起使用的解决方法吗?
我已经用 YAP 版本 6.2.2 和 6.3.2 进行了测试,结果相同。
更新:
正如@sharky 所建议的,显然这是 YAP 二进制文件(或 YAP 的 JPL 端口)的问题。使用 SWI 时,问题中显示的示例运行良好。
我仍然对多线程程序中的 JPL 行为感到困惑。
查看JPL库中Query类中open方法的源代码和cmets:
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 引擎,而不是源代码及其 cmets 似乎暗示的新引擎。
如果有人有 JPL 和多线程方面的经验,请澄清这一点。
【问题讨论】:
-
这是 JPL 的问题还是错误报告?
-
嗨@Daniel,刚刚添加了一个额外的行来澄清最后的问题
-
您是否尝试过使用 SWI 作为后端来查看问题是否出在 YAP 二进制文件中?
-
嗨@sharky,是的,问题似乎出在您建议的 YAP 二进制文件中,因为使用 SWI 没有致命错误。我刚刚用这个更新了这个问题。
-
在第一个例子中,第一个和第三个查询在同一个线程上。从理论上讲,这应该没问题,因为第一个查询在第三个执行之前完成。我猜第二个查询(在单独的线程上)可能与问题无关。如果您删除第二个查询,并在主线程上一个接一个地运行两个查询,是否会发生错误?附: API 文档提到您应该在使用查询后关闭()查询。这可能会很好地解决您的问题。
标签: java multithreading prolog jpl