私はJPLのマルチスレッド機能を実験してきました。ソースコードのコメントから理解できる限り、Javaスレッドごとに1つの異なるPrologエンジンが割り当てられています。明らかに、クエリがスレッドAで開始され、別のクエリがスレッドBで実行され(スレッドAによって生成され)、3番目のクエリがスレッド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のドキュメントには、2つのクエリを同時にアクティブにすることはできないと記載されているため、コードはスレッドが完了するまで待機してから最後のクエリに進みます(その制約が同じスレッドのクエリにのみ適用されるかどうかはまだわかりません)。または、異なるスレッドやエンジンのクエリに適用される場合)。
前の例では、最初の2つのクエリのみが成功します。3番目のクエリを実行すると、次の致命的なエラーが発生します。
#
# 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ライブラリopen
のクラスのメソッドのソースコードとコメントを見てみましょう。Query
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
したがって、明らかに2番目のスレッドは最初のスレッドと同じPrologエンジンにアクセスしており、ソースコードとそのコメントが示唆しているように新しいスレッドではありません。
誰かがJPLとマルチスレッドの経験がある場合は、これを明確にしてください。