1

I have been experimenting with the multithreading features of JPL. As far as I understand from the comments in the source code one different Prolog engine is assigned per Java thread. Apparently there is a problem when a query is started in thread A, another query is executed in thread B (spawned by thread A), and a third query is executed again in thread A.

The following snippet of code illustrates the problem:

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);
    }
}

Since the JPL documentation mentions that no two queries can be active at the same time, the code waits until completion of the thread before continuing to the last query (it is not yet clear to me if that constraint applies only to queries in the same thread or if it applies to queries in different threads and engines).

In the previous example, only the first two queries succeed. When the third query is executed I obtain this fatal error:

#
# 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
#
...

Is this a bug in JPL ? in that case does someone know a workaround for using JPL with multithreading ?

I have tested with both YAP version 6.2.2 and 6.3.2 with the same results.

UPDATE:

As @sharky suggested, apparently it is a problem with the YAP binaries (or the JPL port for YAP). When using SWI the example showed in the question is working fine.

Still I am puzzled with the JPL behavior in multi-threaded programs. Taken a look to the source code and comments of the open method in the Query class from the JPL library:

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();       
  }
  ...
}

it seems to say that JPL will create a new logic engine per thread. However, if I execute this simple program:

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();

I can see the following output:

Thread1 x:true
Thread2 x:true

So apparently the second thread is accessing the same Prolog engine than the first one, not a new one as the source code and its comments seems to suggest.

If someone has experience with JPL and multithreading please clarify this.

Sergio
  • 8,532
  • 11
  • 52
  • 94
  • Is this a question or a bug report for JPL? – Daniel Lyons Oct 09 '12 at 17:04
  • Hi @Daniel, just added an extra line clarifying the question at the end – Sergio Oct 09 '12 at 17:13
  • 1
    Have you tried using SWI as the back-end to see if the problem lies in the YAP binaries? –  Oct 19 '12 at 02:11
  • hi @sharky, yes, the problem seems to be in the YAP binaries as you suggested, since with SWI there is no fatal error. I have just updated the question with this. – Sergio Nov 30 '12 at 23:35
  • 1
    In the first example, the first and third queries are on the same thread. Theoretically, this should be ok, since the first query completes before the third executes. I'm guessing that the second query (on a separate thread) may have no bearing on the problem. Does the error occur if you remove the second query, and simply run two queries, one after the other, on the main thread? P.S. The API documentation mentions that you should close() a query after using it. That may well solve your problem. – GreyBeardedGeek Dec 01 '12 at 00:02
  • hi @GreyBeardedGeek, the problem only occurs if the second query (in the separate thread) is present. The method `hasSolution()` closes the query for me. – Sergio Dec 01 '12 at 00:28

1 Answers1

0

Now I've found possible solution (however there is a way to still access at the defined clauses)

you can use modules! prolog file:

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

then in thread1 you can ask thread1:x and it will succed and thread2 will launch an exception (you can catch it and say failure...) (unless you don't define x dynamic)

another way is use thread_local... but you have to define each clause as thread_local (boring!)