* libguile thread safety
@ 2014-01-03 23:34 Chris Vine
2014-01-04 0:00 ` Ludovic Courtès
` (2 more replies)
0 siblings, 3 replies; 23+ messages in thread
From: Chris Vine @ 2014-01-03 23:34 UTC (permalink / raw)
To: guile-user
Hi,
I am having problems using libguile in a multi-threaded environment,
which boils down to the following small test case, which fails with a
segmentation fault with guile-2.0.9:
#include <libguile.h>
#include <pthread.h>
void *guile_wrapper (void *data) {
scm_c_eval_string ("(display \"Hello\n\")");
return NULL;
}
void *thread_func (void *data) {
scm_with_guile (&guile_wrapper, NULL);
return NULL;
}
int main () {
pthread_t thread1;
pthread_t thread2;
pthread_create (&thread1, NULL, thread_func, NULL);
pthread_create (&thread2, NULL, thread_func, NULL);
pthread_join (thread1, NULL);
pthread_join (thread2, NULL);
return 0;
}
However, it prints "Hello" correctly if only one thread is started.
It seems that scm_with_guile() is not thread safe in the form used
above. However the following suggest that it should be:
http://www.gnu.org/software/guile/manual/html_node/Multi_002dThreading.html#Multi_002dThreading
http://www.gnu.org/software/guile/manual/html_node/Initialization.html#Initialization
I am clearly doing something wrong, which is probably obvious to
others. Can anyone help me with this? Perhaps I have to serialize use
of scm_with_guile() notwithstanding what is said in the documentation,
but if so it will be disappointing for the use to which I was hoping to
put it.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-03 23:34 libguile thread safety Chris Vine
@ 2014-01-04 0:00 ` Ludovic Courtès
2014-01-04 17:19 ` Chris Vine
2014-01-04 0:08 ` Panicz Maciej Godek
2014-01-04 1:59 ` Mark H Weaver
2 siblings, 1 reply; 23+ messages in thread
From: Ludovic Courtès @ 2014-01-04 0:00 UTC (permalink / raw)
To: guile-user
Hi,
Chris Vine <chris@cvine.freeserve.co.uk> skribis:
> I am having problems using libguile in a multi-threaded environment,
> which boils down to the following small test case, which fails with a
> segmentation fault with guile-2.0.9:
>
> #include <libguile.h>
> #include <pthread.h>
>
> void *guile_wrapper (void *data) {
> scm_c_eval_string ("(display \"Hello\n\")");
> return NULL;
> }
>
> void *thread_func (void *data) {
> scm_with_guile (&guile_wrapper, NULL);
> return NULL;
> }
>
> int main () {
> pthread_t thread1;
> pthread_t thread2;
>
> pthread_create (&thread1, NULL, thread_func, NULL);
> pthread_create (&thread2, NULL, thread_func, NULL);
>
> pthread_join (thread1, NULL);
> pthread_join (thread2, NULL);
> return 0;
> }
This should work (but see below.) In fact, this is what
test-pthread-create-secondary.c tests (in Guile’s test suite.)
It may fail if libgc was built without pthread support, or if it’s an
old version (older than 7.2alpha6). Could you check that?
However, ports themselves are not thread-safe in 2.0, and the code above
has several threads writing to the current output port, which is a
problem. When an application has several threads using the same port,
it must do its own locking currently.
Thanks,
Ludo’.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-03 23:34 libguile thread safety Chris Vine
2014-01-04 0:00 ` Ludovic Courtès
@ 2014-01-04 0:08 ` Panicz Maciej Godek
2014-01-04 0:22 ` Chris Vine
2014-01-04 1:59 ` Mark H Weaver
2 siblings, 1 reply; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-04 0:08 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
Hi,
I have never used the pthread library directly, but would it be
possible for your program to use scm_spawn_thread instead? (according
to the manual, it starts a new thread in guile mode, but I guess it
needs to be run in guile mode as well)
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 0:08 ` Panicz Maciej Godek
@ 2014-01-04 0:22 ` Chris Vine
2014-01-04 0:56 ` Panicz Maciej Godek
0 siblings, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-01-04 0:22 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user@gnu.org
On Sat, 4 Jan 2014 01:08:12 +0100
Panicz Maciej Godek <godek.maciek@gmail.com> wrote:
> Hi,
> I have never used the pthread library directly, but would it be
> possible for your program to use scm_spawn_thread instead? (according
> to the manual, it starts a new thread in guile mode, but I guess it
> needs to be run in guile mode as well)
That wouldn't help in my usage case I am afraid. Essentially I am
trying to integrate some scheme code with some C++ code, which involves
running callable objects (tasks) on a thread pool. Some will be native
C++ lambdas or other function objects, and some will be scheme code I
was intending to run on the guile VM. That seemed a natural fit for
libguile, but I was getting intermittent crashes when two tasks
involving scheme code on the VM tried to start at approximately the same
time.
I was hoping there was something obvious in the test case that I was
doing wrong. On the other hand, if it is a guile bug then I will have
to see if I can work around it. If I can't, I may have to abandon this
aspect of the project and go C++ only. If I have to serialize all
running of scheme code on libguile it would slow other stuff down too
much.
I am still hopeful someone will tell me I have got something wrong in
the test case.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 0:22 ` Chris Vine
@ 2014-01-04 0:56 ` Panicz Maciej Godek
2014-01-04 1:22 ` Panicz Maciej Godek
0 siblings, 1 reply; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-04 0:56 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
The code looks fine to me. It seems that there's a bug in guile --
when I insert one second sleep between the two invocations of
pthread_create, everything works fine. However, when I go down with
the sleep time below ~50000 microseconds, things are getting weird.
The good news is that the problem appears only between the first and
the second invocation, but if you wait after creation of the first
thread, then everything seems OK.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 0:56 ` Panicz Maciej Godek
@ 2014-01-04 1:22 ` Panicz Maciej Godek
2014-01-04 9:39 ` Chris Vine
0 siblings, 1 reply; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-04 1:22 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
I concluded that this might be a solution. I tested it with 2.0.5 from
ubuntu repository. I had to add GC_allow_register_threads (and link
against gc, accordingly), because otherwise the program aborted with
the message "Threads explicit registering is not previously enabled"
whenever it attempted to create a thread.
For some reason the initialization routine needs to call
scm_c_eval_string; otherwise it doesn't help.
The solution doesn't fill me with joy, but I hope it works for you
#include <libguile.h>
#include <pthread.h>
void *guile_wrapper (void *data) {
scm_c_eval_string ("(display \"Hello\n\")");
return NULL;
}
void *thread_func (void *data) {
scm_with_guile (&guile_wrapper, NULL);
return NULL;
}
void *do_nothing(void *unused) {
scm_c_eval_string("(noop)");
return NULL;
}
int main () {
pthread_t thread1;
pthread_t thread2;
GC_allow_register_threads();
scm_with_guile(do_nothing, NULL);
pthread_create (&thread1, NULL, thread_func, NULL);
pthread_create (&thread2, NULL, thread_func, NULL);
pthread_join (thread1, NULL);
pthread_join (thread2, NULL);
return 0;
}
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-03 23:34 libguile thread safety Chris Vine
2014-01-04 0:00 ` Ludovic Courtès
2014-01-04 0:08 ` Panicz Maciej Godek
@ 2014-01-04 1:59 ` Mark H Weaver
2014-01-04 9:50 ` Chris Vine
2014-01-04 12:44 ` Chris Vine
2 siblings, 2 replies; 23+ messages in thread
From: Mark H Weaver @ 2014-01-04 1:59 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user
Chris Vine <chris@cvine.freeserve.co.uk> writes:
> I am having problems using libguile in a multi-threaded environment,
> which boils down to the following small test case, which fails with a
> segmentation fault with guile-2.0.9:
I've recently noticed that the module loading process in Guile is not
thread safe. I hope to fix this in the next month or two, but for now
I'd recommend that one thread should initialize Guile and load the
modules that will be needed, before allowing multiple threads to enter
Guile mode.
Regards,
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 1:22 ` Panicz Maciej Godek
@ 2014-01-04 9:39 ` Chris Vine
2014-01-04 21:28 ` Mark H Weaver
0 siblings, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-01-04 9:39 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user@gnu.org
On Sat, 4 Jan 2014 02:22:11 +0100
Panicz Maciej Godek <godek.maciek@gmail.com> wrote:
> I concluded that this might be a solution. I tested it with 2.0.5 from
> ubuntu repository. I had to add GC_allow_register_threads (and link
> against gc, accordingly), because otherwise the program aborted with
> the message "Threads explicit registering is not previously enabled"
> whenever it attempted to create a thread.
>
> For some reason the initialization routine needs to call
> scm_c_eval_string; otherwise it doesn't help.
>
> The solution doesn't fill me with joy, but I hope it works for you
Cool.
Your revised test case appears to work on guile-2.0.9 without calling
GC_allow_register_threads(). Subject to further testing the key seems
to be to allow one thread to complete a call to scm_with_guile() and
scm_c_eval_string() before any new one is allowed to do anything. On
further testing (involving inserting my own synchronization and using
scm_init_guile()) it appears that none of scm_with_guile(),
scm_init_guile() and scm_c_eval_string() are thread safe on the first
call. They seem to do some initial set up on first call which is not
done in a thread safe way.
By way of example, for me this also works (does it work for
guile-2.0.5?):
#include <libguile.h>
#include <pthread.h>
void *guile_wrapper (void *data) {
scm_c_eval_string ("(display \"Hello\n\")");
return NULL;
}
void *thread_func (void *data) {
scm_with_guile (&guile_wrapper, NULL);
return NULL;
}
int main () {
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
/* initialize */
pthread_create (&thread1, NULL, thread_func, NULL);
pthread_join (thread1, NULL);
/* proceed with other threads */
pthread_create (&thread2, NULL, thread_func, NULL);
pthread_create (&thread3, NULL, thread_func, NULL);
pthread_join (thread2, NULL);
pthread_join (thread3, NULL);
return 0;
}
Unfortunately, from what Mark Weaver says, the module system doesn't
initialize itself in a thread safe way either :(. That is more
problematic because you might not know in advance what modules are to
be loaded by any particular code. The task model isn't suppose to
import cross-dependencies of that kind.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 1:59 ` Mark H Weaver
@ 2014-01-04 9:50 ` Chris Vine
2014-01-04 12:44 ` Chris Vine
1 sibling, 0 replies; 23+ messages in thread
From: Chris Vine @ 2014-01-04 9:50 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-user
On Fri, 03 Jan 2014 20:59:16 -0500
Mark H Weaver <mhw@netris.org> wrote:
> Chris Vine <chris@cvine.freeserve.co.uk> writes:
> > I am having problems using libguile in a multi-threaded environment,
> > which boils down to the following small test case, which fails with
> > a segmentation fault with guile-2.0.9:
>
> I've recently noticed that the module loading process in Guile is not
> thread safe. I hope to fix this in the next month or two, but for now
> I'd recommend that one thread should initialize Guile and load the
> modules that will be needed, before allowing multiple threads to enter
> Guile mode.
Mark,
OK. From my exchanges with Panicz Maciej Godek it appears that none of
scm_with_guile(), scm_init_guile() and scm_c_eval_string() initialize
in a thread safe way on the first call. That may be connected with the
module system, or something else (the test case does not explicitly
load any modules).
If you land anything which you would like me to test, let me know.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 1:59 ` Mark H Weaver
2014-01-04 9:50 ` Chris Vine
@ 2014-01-04 12:44 ` Chris Vine
2014-01-04 15:01 ` Panicz Maciej Godek
1 sibling, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-01-04 12:44 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-user
On Fri, 03 Jan 2014 20:59:16 -0500
Mark H Weaver <mhw@netris.org> wrote:
> Chris Vine <chris@cvine.freeserve.co.uk> writes:
> > I am having problems using libguile in a multi-threaded environment,
> > which boils down to the following small test case, which fails with
> > a segmentation fault with guile-2.0.9:
>
> I've recently noticed that the module loading process in Guile is not
> thread safe. I hope to fix this in the next month or two, but for now
> I'd recommend that one thread should initialize Guile and load the
> modules that will be needed, before allowing multiple threads to enter
> Guile mode.
There is something even more bizarre than as reported in the exchange
with Maciej. The further test case below prints:
Hello
20
20
I would have expected:
Hello
10
20
It seems as if top level variables in code evaluated by scm_c_eval_string()
are shared between concurrently running threads. Is this really the
intended behaviour (it is a significant and unexpected usability
restriction)? Maciej (I hope that is your first name) can you reproduce
this?
Chris
#include <libguile.h>
#include <pthread.h>
void *guile_wrapper1 (void *data) {
scm_c_eval_string("(display \"Hello\n\")");
return NULL;
}
void *guile_wrapper2 (void *data) {
scm_c_eval_string("(define val 10) (usleep 200000)(display val)(newline)");
return NULL;
}
void *guile_wrapper3 (void *data) {
scm_c_eval_string("(usleep 100000) (define val 20) (display val)(newline)");
return NULL;
}
void *thread_func1 (void *data) {
scm_with_guile(&guile_wrapper1, NULL);
return NULL;
}
void *thread_func2 (void *data) {
scm_with_guile(&guile_wrapper2, NULL);
return NULL;
}
void *thread_func3 (void *data) {
scm_with_guile(&guile_wrapper3, NULL);
return NULL;
}
int main () {
pthread_t thread1;
pthread_t thread2;
pthread_t thread3;
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_join(thread1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_create(&thread3, NULL, thread_func3, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
return 0;
}
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 12:44 ` Chris Vine
@ 2014-01-04 15:01 ` Panicz Maciej Godek
2014-01-04 17:16 ` Chris Vine
2014-01-04 19:37 ` Mark H Weaver
0 siblings, 2 replies; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-04 15:01 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
2014/1/4 Chris Vine <chris@cvine.freeserve.co.uk>:
> There is something even more bizarre than as reported in the exchange
> with Maciej. The further test case below prints:
>
> Hello
> 20
> 20
>
> I would have expected:
>
> Hello
> 10
> 20
>
> It seems as if top level variables in code evaluated by scm_c_eval_string()
> are shared between concurrently running threads. Is this really the
> intended behaviour (it is a significant and unexpected usability
> restriction)? Maciej (I hope that is your first name) can you reproduce
> this?
Yes, I confirm that the output with my setup is
Hello
20
20
It indeed does seem that the threads share their top-level bindings on
guile's side, and I suppose that this is the intended behaviour. I
think that it can be easily adjusted with scm_eval_string_in_module,
i.e. if you provide a separate module for each thread.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 15:01 ` Panicz Maciej Godek
@ 2014-01-04 17:16 ` Chris Vine
2014-01-04 19:37 ` Mark H Weaver
1 sibling, 0 replies; 23+ messages in thread
From: Chris Vine @ 2014-01-04 17:16 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user@gnu.org
On Sat, 4 Jan 2014 16:01:35 +0100
Panicz Maciej Godek <godek.maciek@gmail.com> wrote:
[snip]
> It indeed does seem that the threads share their top-level bindings on
> guile's side, and I suppose that this is the intended behaviour. I
> think that it can be easily adjusted with scm_eval_string_in_module,
> i.e. if you provide a separate module for each thread.
Ye gods.
Your suggestion seems the way to go. However, having a separate module
for each thread is not really a runner with a thread pool. Instead of
doing this on a thread-by-thread basis, it would instead be necessary to
create a new module on the fly for each task. Most variables could of
course be wrapped in an overarching lambda or let expression
encapsulating the task, but there will still be some top level variables
to be exported to the task that the code will need to see.
Is there any procedure to obtain a unique random name in guile?
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 0:00 ` Ludovic Courtès
@ 2014-01-04 17:19 ` Chris Vine
0 siblings, 0 replies; 23+ messages in thread
From: Chris Vine @ 2014-01-04 17:19 UTC (permalink / raw)
To: Ludovic Courtès; +Cc: guile-user
On Sat, 04 Jan 2014 01:00:46 +0100
ludo@gnu.org (Ludovic Courtès) wrote:
> Chris Vine <chris@cvine.freeserve.co.uk> skribis:
>
> > I am having problems using libguile in a multi-threaded environment,
> > which boils down to the following small test case, which fails with
> > a segmentation fault with guile-2.0.9:
> >
> > #include <libguile.h>
> > #include <pthread.h>
> >
> > void *guile_wrapper (void *data) {
> > scm_c_eval_string ("(display \"Hello\n\")");
> > return NULL;
> > }
> >
> > void *thread_func (void *data) {
> > scm_with_guile (&guile_wrapper, NULL);
> > return NULL;
> > }
> >
> > int main () {
> > pthread_t thread1;
> > pthread_t thread2;
> >
> > pthread_create (&thread1, NULL, thread_func, NULL);
> > pthread_create (&thread2, NULL, thread_func, NULL);
> >
> > pthread_join (thread1, NULL);
> > pthread_join (thread2, NULL);
> > return 0;
> > }
>
> This should work (but see below.) In fact, this is what
> test-pthread-create-secondary.c tests (in Guile’s test suite.)
>
> It may fail if libgc was built without pthread support, or if it’s an
> old version (older than 7.2alpha6). Could you check that?
>
> However, ports themselves are not thread-safe in 2.0, and the code
> above has several threads writing to the current output port, which
> is a problem. When an application has several threads using the same
> port, it must do its own locking currently.
I am using gc-7.2d, and objdump -p shows that libgc.so.1 has a hard
linking dependency on libpthread, so it looks as if it is compiled with
thread support. You will see from later postings that this problem can
be avoided by allowing one thread to initialize scm_with_guile() and
scm_c_eval_string() to completion before any others attempt to do so.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 15:01 ` Panicz Maciej Godek
2014-01-04 17:16 ` Chris Vine
@ 2014-01-04 19:37 ` Mark H Weaver
2014-01-04 21:01 ` Chris Vine
1 sibling, 1 reply; 23+ messages in thread
From: Mark H Weaver @ 2014-01-04 19:37 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user
Panicz Maciej Godek <godek.maciek@gmail.com> writes:
> 2014/1/4 Chris Vine <chris@cvine.freeserve.co.uk>:
>> It seems as if top level variables in code evaluated by scm_c_eval_string()
>> are shared between concurrently running threads. Is this really the
>> intended behaviour (it is a significant and unexpected usability
>> restriction)? Maciej (I hope that is your first name) can you reproduce
>> this?
>
[...]
>
> It indeed does seem that the threads share their top-level bindings on
> guile's side, and I suppose that this is the intended behaviour. I
> think that it can be easily adjusted with scm_eval_string_in_module,
> i.e. if you provide a separate module for each thread.
Indeed, top-level bindings are always looked up in the "current module".
Each thread has its own "current module", but 'scm_with_guile' initially
sets the current module to (guile-user). That's usually desirable,
because you may have bound your own application-specific procedures and
global variables in (guile-user), and you want all threads to have
access to those by default.
The usual way to make thread-local variables in Guile is to use
parameters[1] or fluids[2]. It's rather unusual to create fresh modules
for each thread, but if you really want to do that you can start each
thread by evaluating "(set-current-module (make-fresh-user-module))".
[1] API Reference > Scheduling > Parameters (section 6.21.8)
[2] API Reference > Scheduling > Fluids and Dynamic States (section 6.21.7)
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 19:37 ` Mark H Weaver
@ 2014-01-04 21:01 ` Chris Vine
2014-01-04 22:43 ` Panicz Maciej Godek
0 siblings, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-01-04 21:01 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-user
On Sat, 04 Jan 2014 14:37:59 -0500
Mark H Weaver <mhw@netris.org> wrote:
> Indeed, top-level bindings are always looked up in the "current
> module". Each thread has its own "current module", but
> 'scm_with_guile' initially sets the current module to (guile-user).
> That's usually desirable, because you may have bound your own
> application-specific procedures and global variables in (guile-user),
> and you want all threads to have access to those by default.
>
> The usual way to make thread-local variables in Guile is to use
> parameters[1] or fluids[2]. It's rather unusual to create fresh
> modules for each thread, but if you really want to do that you can
> start each thread by evaluating "(set-current-module
> (make-fresh-user-module))".
>
> [1] API Reference > Scheduling > Parameters (section 6.21.8)
> [2] API Reference > Scheduling > Fluids and Dynamic States (section
> 6.21.7)
That's great. Both using parameters and changing the current module to
one obtained by make-fresh-user-module works, but changing the current
module is the best fit for what I want to do with this. Is it
efficiency concerns that make you think it unusual, or just that the
use case is unusual? (For anyone calling scm_c_eval_string() in a
multi-threaded program, as opposed to evaluating eval at the REPL, I
should have thought a fresh module was just what they wanted.)
make-fresh-user-module is not documented. It might be worth adding it
to the documentation.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 9:39 ` Chris Vine
@ 2014-01-04 21:28 ` Mark H Weaver
0 siblings, 0 replies; 23+ messages in thread
From: Mark H Weaver @ 2014-01-04 21:28 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user
Chris Vine <chris@cvine.freeserve.co.uk> writes:
> Unfortunately, from what Mark Weaver says, the module system doesn't
> initialize itself in a thread safe way either :(.
That's not quite right. It initializes itself in a thread safe way.
However, _after_ initialization, it does not load modules in a thread
safe way.
> That is more problematic because you might not know in advance what
> modules are to be loaded by any particular code. The task model isn't
> suppose to import cross-dependencies of that kind.
I can see that this is a serious problem, and I'm going to focus on
fixing it properly and soon, hopefully in the next two weeks.
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 21:01 ` Chris Vine
@ 2014-01-04 22:43 ` Panicz Maciej Godek
2014-01-04 23:31 ` Chris Vine
0 siblings, 1 reply; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-04 22:43 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
2014/1/4 Chris Vine <chris@cvine.freeserve.co.uk>:
> Is it efficiency concerns that make you think it unusual, or just that the
> use case is unusual?
I don't think that creating a new module is particularly inefficient,
and it would only become noticable if you were creating many many
threads with a short lifetime. What's unusual (and I think that Mark
would agree) is that you'd normally want your thread to be able to
access all the definitions that are visible to the program (or: to the
main thread). If a program is written in a functional style, the
threads usually don't mutate their global environment -- they just
read the definitions -- so any race conditions or other conflicts are
unlikely.
I think that your use-case is different and that you make very few
assumptions on the code that the threads will execute -- in
particular, that it might be a highly imperative code which does
mutate its global state. If it is so, then I think that this is the
right way. (Be warned, that it doesn't protect the system from
malicious code -- it is still possible for a thread to modify the
content of another module, but it's difficult to do that by accident)
> make-fresh-user-module is not documented. It might be worth adding it
> to the documentation.
it definitely might ;)
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 22:43 ` Panicz Maciej Godek
@ 2014-01-04 23:31 ` Chris Vine
2014-01-05 13:15 ` Panicz Maciej Godek
0 siblings, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-01-04 23:31 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user@gnu.org
On Sat, 4 Jan 2014 23:43:22 +0100
Panicz Maciej Godek <godek.maciek@gmail.com> wrote:
> 2014/1/4 Chris Vine <chris@cvine.freeserve.co.uk>:
> > Is it efficiency concerns that make you think it unusual, or just
> > that the use case is unusual?
>
> I don't think that creating a new module is particularly inefficient,
> and it would only become noticable if you were creating many many
> threads with a short lifetime. What's unusual (and I think that Mark
> would agree) is that you'd normally want your thread to be able to
> access all the definitions that are visible to the program (or: to the
> main thread). If a program is written in a functional style, the
> threads usually don't mutate their global environment -- they just
> read the definitions -- so any race conditions or other conflicts are
> unlikely.
>
> I think that your use-case is different and that you make very few
> assumptions on the code that the threads will execute -- in
> particular, that it might be a highly imperative code which does
> mutate its global state. If it is so, then I think that this is the
> right way. (Be warned, that it doesn't protect the system from
> malicious code -- it is still possible for a thread to modify the
> content of another module, but it's difficult to do that by accident)
The problem here isn't so much deliberate mutation of data, as top level
name clashes causing silent unwanted mutation.
But yes, in this usage task isolation is a positive virtue, not
something to be regretted. We can assume no malicious intent (the
house-keeping of any thread pool can be wrecked by the simple expedient
of a task calling pthread_exit(): one must assume some competence and
good faith on the part of the programmer). One purpose of top level
variables at the module level here is to pass arguments to loaded scheme
files.
I actually have a prototype working well now, apart from the module
issue Mark Weaver referred to, which I have to say has not yet bitten me
but no doubt might.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-04 23:31 ` Chris Vine
@ 2014-01-05 13:15 ` Panicz Maciej Godek
2014-01-05 17:37 ` Mark H Weaver
0 siblings, 1 reply; 23+ messages in thread
From: Panicz Maciej Godek @ 2014-01-05 13:15 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user@gnu.org
2014/1/5 Chris Vine <chris@cvine.freeserve.co.uk>:
> I actually have a prototype working well now, apart from the module
> issue Mark Weaver referred to, which I have to say has not yet bitten me
> but no doubt might.
If you are worried about this, you could try to take your own
precautions and redefine the "use-modules" syntax (or others, like
"resolve-module", if you are planning to use them) to make sure that
it is thread safe.
The sole act of redefinition would require you to create a new module like this:
(define-module (safe-modules)
#:use-module (ice-9 format)
#:replace ((safe-use-modules . use-modules)))
(define-syntax-rule (safe-use-modules modules ...)
(begin
(format #t "loading modules ~a... " '(modules ...))
(use-modules modules ...)
(format #t "done!\n")))
You'd need to replace the the messages with some thread
synchronization mechanism, to make sure that if one thread calls
"use-modules", all the others that would try to do that at that time
would have to wait.
I don't know if that would resolve all the problems concerning the
issue, because I don't know the guts of the module system. Perhaps
some other situations would need to be considered, in particular error
handling (to make sure, that an error in one module doesn't cause
other threads to wait forever).
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-05 13:15 ` Panicz Maciej Godek
@ 2014-01-05 17:37 ` Mark H Weaver
2014-03-18 10:49 ` Chris Vine
0 siblings, 1 reply; 23+ messages in thread
From: Mark H Weaver @ 2014-01-05 17:37 UTC (permalink / raw)
To: Panicz Maciej Godek; +Cc: guile-user
Panicz Maciej Godek <godek.maciek@gmail.com> writes:
> 2014/1/5 Chris Vine <chris@cvine.freeserve.co.uk>:
>
>> I actually have a prototype working well now, apart from the module
>> issue Mark Weaver referred to, which I have to say has not yet bitten me
>> but no doubt might.
>
> If you are worried about this, you could try to take your own
> precautions and redefine the "use-modules" syntax (or others, like
> "resolve-module", if you are planning to use them) to make sure that
> it is thread safe.
>
> The sole act of redefinition would require you to create a new module like this:
> (define-module (safe-modules)
> #:use-module (ice-9 format)
> #:replace ((safe-use-modules . use-modules)))
>
> (define-syntax-rule (safe-use-modules modules ...)
> (begin
> (format #t "loading modules ~a... " '(modules ...))
> (use-modules modules ...)
> (format #t "done!\n")))
>
> You'd need to replace the the messages with some thread
> synchronization mechanism, to make sure that if one thread calls
> "use-modules", all the others that would try to do that at that time
> would have to wait.
This wouldn't work. First of all, 'use-modules' is a macro, not a
procedure, but more importantly, modules are autoloaded in many places
deep in the guts of the system. Notice that Chris' test cases didn't
use 'use-modules' at all. In fact, a module is autoloaded the first
time 'scm_c_eval_string' is called. Also, there are potential
deadlocks.
We should just fix the problem properly, and that's what I intend to do.
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-01-05 17:37 ` Mark H Weaver
@ 2014-03-18 10:49 ` Chris Vine
2014-03-18 15:22 ` Mark H Weaver
0 siblings, 1 reply; 23+ messages in thread
From: Chris Vine @ 2014-03-18 10:49 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-user
On Sun, 05 Jan 2014 12:37:29 -0500
Mark H Weaver <mhw@netris.org> wrote:
[snip]
> This wouldn't work. First of all, 'use-modules' is a macro, not a
> procedure, but more importantly, modules are autoloaded in many places
> deep in the guts of the system. Notice that Chris' test cases didn't
> use 'use-modules' at all. In fact, a module is autoloaded the first
> time 'scm_c_eval_string' is called. Also, there are potential
> deadlocks.
>
> We should just fix the problem properly, and that's what I intend to
> do.
I notice that the thread-safe initialization of guile by
scm_with_guile() seems to have been fixed in guile-2.0.10, but the
loading of modules remains not thread-safe.
Has thread-safe module loading turned out to be too difficult to do, or
is it still something that is likely to happen in the future?
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-03-18 10:49 ` Chris Vine
@ 2014-03-18 15:22 ` Mark H Weaver
2014-03-18 19:32 ` Chris Vine
0 siblings, 1 reply; 23+ messages in thread
From: Mark H Weaver @ 2014-03-18 15:22 UTC (permalink / raw)
To: Chris Vine; +Cc: guile-user
Chris Vine <chris@cvine.freeserve.co.uk> writes:
> Has thread-safe module loading turned out to be too difficult to do, or
> is it still something that is likely to happen in the future?
I consider this to be an important issue, and I still intend to fix it.
However, fixing it in such a way that I could confidently believe would
not cause problems for existing users (who might do unusual things with
Guile's module system) is indeed non-trivial.
On the other hand, the lack of thread-safety in module loading doesn't
seem to be causing problems for most users in practice. I suspect this
is because most programs load their modules during initialization, and
rarely (if ever) load modules afterwards.
Therefore, I'm considering fixing this in git master, which will become
Guile 2.2, and not in the stable-2.0 branch.
What do you think?
Mark
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: libguile thread safety
2014-03-18 15:22 ` Mark H Weaver
@ 2014-03-18 19:32 ` Chris Vine
0 siblings, 0 replies; 23+ messages in thread
From: Chris Vine @ 2014-03-18 19:32 UTC (permalink / raw)
To: Mark H Weaver; +Cc: guile-user
On Tue, 18 Mar 2014 11:22:13 -0400
Mark H Weaver <mhw@netris.org> wrote:
> Chris Vine <chris@cvine.freeserve.co.uk> writes:
>
> > Has thread-safe module loading turned out to be too difficult to
> > do, or is it still something that is likely to happen in the future?
>
> I consider this to be an important issue, and I still intend to fix
> it. However, fixing it in such a way that I could confidently believe
> would not cause problems for existing users (who might do unusual
> things with Guile's module system) is indeed non-trivial.
>
> On the other hand, the lack of thread-safety in module loading doesn't
> seem to be causing problems for most users in practice. I suspect
> this is because most programs load their modules during
> initialization, and rarely (if ever) load modules afterwards.
>
> Therefore, I'm considering fixing this in git master, which will
> become Guile 2.2, and not in the stable-2.0 branch.
>
> What do you think?
I am a user and know little of the internal implementation details of
libguile, so I think you are better able to assess the likelihood of
disruption to other guile-2.0 users. The achievable seems better than
looking for perfection.
I have found libguile quite useful for asynchronous text processing in
C++ programs, and because it was simple to implement I have included
provision for it in a small library I maintain:
http://cxx-gtk-utils.sourceforge.net/2.2/namespaceCgu_1_1Extension.html .
I guess that that is the extent of my stake in the issue.
Chris
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2014-03-18 19:32 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-03 23:34 libguile thread safety Chris Vine
2014-01-04 0:00 ` Ludovic Courtès
2014-01-04 17:19 ` Chris Vine
2014-01-04 0:08 ` Panicz Maciej Godek
2014-01-04 0:22 ` Chris Vine
2014-01-04 0:56 ` Panicz Maciej Godek
2014-01-04 1:22 ` Panicz Maciej Godek
2014-01-04 9:39 ` Chris Vine
2014-01-04 21:28 ` Mark H Weaver
2014-01-04 1:59 ` Mark H Weaver
2014-01-04 9:50 ` Chris Vine
2014-01-04 12:44 ` Chris Vine
2014-01-04 15:01 ` Panicz Maciej Godek
2014-01-04 17:16 ` Chris Vine
2014-01-04 19:37 ` Mark H Weaver
2014-01-04 21:01 ` Chris Vine
2014-01-04 22:43 ` Panicz Maciej Godek
2014-01-04 23:31 ` Chris Vine
2014-01-05 13:15 ` Panicz Maciej Godek
2014-01-05 17:37 ` Mark H Weaver
2014-03-18 10:49 ` Chris Vine
2014-03-18 15:22 ` Mark H Weaver
2014-03-18 19:32 ` Chris Vine
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).