How to use classes of C++ interface of swipl in a thread?

Hi,
I’ve found program always crashes in swipl if any classes of C++ library of swipl are used in a thread. e.g.

PREDICATE(test_thread, 0) {
  PlCompound term("hello", PlTermv("world"));
  thread t([&] { cout << (char *)term << endl; });
  t.join();
  return TRUE;
}

test_thread/0 always results in swipl to crash.
?- ddtest:test_thread.

SWI-Prolog [thread -1 () at Wed Aug 21 15:19:03 2019]: received fatal signal 11 (segv)
C-stack trace labeled “crash”:
[0] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(save_backtrace+0x62) [0x102f23042]
[1] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(print_c_backtrace+0x15) [0x102f23915]
[2] /usr/local/Cellar/swi-prolog/HEAD-ad9b759/libexec/lib/swipl/lib/x86_64-darwin/libswipl.8.dylib(sigCrashHandler+0xf4) [0x102f23824]

I have no idea that what I miss.
Thanks for any helps!

With best regards,
Arthur Wang

Please read https://www.swi-prolog.org/pldoc/man?section=foreignthread

That will probably answer your question.

Dear Jan,
Thank you very much for the information!
But I hav’t got how to communicate data between prolog engine thread and calling thread. e.g. how to return A1 in the snippet below:

PREDICATE(test_thread, 1) {
  thread t([&] {
    PL_thread_attach_engine(NULL);
    PlTerm term("hello");
    cout << "term:" << (char *)term << endl;
    A1 = term;
    PL_thread_destroy_engine();
  });
  t.join();
  return TRUE;
}

?- ddtest:test_thread(T).
term:hello
true.

A1 is not passed out.

With regards,
Arthur

Terms, as in term_t or its C++ equivalent PlTerm are restricted to a single thread. I’d try to avoid the kind of stuff you are doing there as much as possible. Let Prolog create the threads and let C++ do the things in those threads that Prolog cannot do (well). If that doesn’t work, let the C++ main program create the threads and attach a Prolog thread to those that need Prolog (or have one or more Prolog engines hopping around between the C++ threads that need Prolog).

If you want to do stuff like that you can use PL_record(), PL_recorded() and PL_erase() to communicate the term as a record from one thread to another. That is also what happens between Prolog threads for the goal passed to a new thread as well as terms send to another thread using a message queue.

In my experience the most productive way is to use C++ is for defining additional predicates. and do all the rest in Prolog. If the main program must for some reason be in C++ you can still do that: your C++ main simply initializes Prolog and passes control to Prolog. It also saves you a lot of recompilation :slight_smile:

1 Like

Thank you so much for clarification: terms are restricted in single thread! I’ll let C++ and swipl do what they are good at and do best to avoid interleaving. :slight_smile:

Kind regards,
Arthur

In the Qt console there are several places where inter thread communication is needed.
Maybe you could find useful the helper exec_sync. Clearly, it doesn’t address exchanging term_t, it just offers a pattern to avoid race conditions with lambdas - that I think are present at least in your first example.

PREDICATE0(tty_clear) {
    ConsoleEdit* c = console_by_thread();
    if (c) {

        // loqt does better...
        // pqConsole::gui_run([&]() { c->tty_clear(); });

        ConsoleEdit::exec_sync s;
        c->exec_func([&]() {
            c->tty_clear();
            s.go();
        });
        s.stop();

        // buggy - need to sync
        // c->tty_clear();

        return TRUE;
    }
    return FALSE;
}

HTH, Carlo

Thank you Carlo for a helpful hint to handle race condition :slight_smile:

Arthur