繁体   English   中英

JPL库在多线程程序中的意外行为(接口Java和Prolog)

[英]Unexpected behavior of the JPL library in multithreaded programs (Interfacing Java and Prolog)

我一直在尝试JPL的多线程功能。 据我从源代码中的注释了解,每个Java线程分配了一个不同的Prolog引擎。 显然,当在线程A中启动查询,在线程B中执行另一个查询(由线程A生成)并在线程A中再次执行第三个查询时,存在一个问题。

下面的代码片段说明了该问题:

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方法的源代码和注释:

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引擎,而不是源代码及其注释所暗示的新线程。

如果某人有使用JPL和多线程的经验,请对此进行说明。

现在,我找到了可能的解决方案(但是仍然有一种方法可以访问已定义的子句)

您可以使用模块! 序言文件:

:-module(thread1,[]).
x.

然后在thread1中,您可以询问thread1:x ,它将成功并且thread2将启动异常(您可以捕获它并说失败...)(除非您不定义x dynamic)

另一种方法是使用thread_local ...,但您必须将每个子句定义为thread_local(很无聊!)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM