253 lines
12 KiB
HTML
253 lines
12 KiB
HTML
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<!-- Created by GNU Texinfo 7.1, https://www.gnu.org/software/texinfo/ -->
|
||
|
<head>
|
||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||
|
<!-- This manual documents Guile version 3.0.10.
|
||
|
|
||
|
Copyright (C) 1996-1997, 2000-2005, 2009-2023 Free Software Foundation,
|
||
|
Inc.
|
||
|
|
||
|
Copyright (C) 2021 Maxime Devos
|
||
|
|
||
|
Copyright (C) 2024 Tomas Volf
|
||
|
|
||
|
|
||
|
Permission is granted to copy, distribute and/or modify this document
|
||
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||
|
any later version published by the Free Software Foundation; with no
|
||
|
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
|
||
|
copy of the license is included in the section entitled "GNU Free
|
||
|
Documentation License." -->
|
||
|
<title>Multi-Threading (Guile Reference Manual)</title>
|
||
|
|
||
|
<meta name="description" content="Multi-Threading (Guile Reference Manual)">
|
||
|
<meta name="keywords" content="Multi-Threading (Guile Reference Manual)">
|
||
|
<meta name="resource-type" content="document">
|
||
|
<meta name="distribution" content="global">
|
||
|
<meta name="Generator" content=".texi2any-real">
|
||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
|
|
||
|
<link href="index.html" rel="start" title="Top">
|
||
|
<link href="Concept-Index.html" rel="index" title="Concept Index">
|
||
|
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
|
||
|
<link href="General-Libguile-Concepts.html" rel="up" title="General Libguile Concepts">
|
||
|
<link href="Asynchronous-Signals.html" rel="prev" title="Asynchronous Signals">
|
||
|
<style type="text/css">
|
||
|
<!--
|
||
|
a.copiable-link {visibility: hidden; text-decoration: none; line-height: 0em}
|
||
|
div.example {margin-left: 3.2em}
|
||
|
span:hover a.copiable-link {visibility: visible}
|
||
|
-->
|
||
|
</style>
|
||
|
<link rel="stylesheet" type="text/css" href="https://www.gnu.org/software/gnulib/manual.css">
|
||
|
|
||
|
|
||
|
</head>
|
||
|
|
||
|
<body lang="en">
|
||
|
<div class="subsection-level-extent" id="Multi_002dThreading">
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Previous: <a href="Asynchronous-Signals.html" accesskey="p" rel="prev">Asynchronous Signals</a>, Up: <a href="General-Libguile-Concepts.html" accesskey="u" rel="up">General concepts for using libguile</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
<hr>
|
||
|
<h4 class="subsection" id="Multi_002dThreading-1"><span>5.4.5 Multi-Threading<a class="copiable-link" href="#Multi_002dThreading-1"> ¶</a></span></h4>
|
||
|
|
||
|
<p>Guile can be used in multi-threaded programs just as well as in
|
||
|
single-threaded ones.
|
||
|
</p>
|
||
|
<p>Each thread that wants to use functions from libguile must put itself
|
||
|
into <em class="emph">guile mode</em> and must then follow a few rules. If it doesn’t
|
||
|
want to honor these rules in certain situations, a thread can
|
||
|
temporarily leave guile mode (but can no longer use libguile functions
|
||
|
during that time, of course).
|
||
|
</p>
|
||
|
<p>Threads enter guile mode by calling <code class="code">scm_with_guile</code>,
|
||
|
<code class="code">scm_boot_guile</code>, or <code class="code">scm_init_guile</code>. As explained in the
|
||
|
reference documentation for these functions, Guile will then learn about
|
||
|
the stack bounds of the thread and can protect the <code class="code">SCM</code> values
|
||
|
that are stored in local variables. When a thread puts itself into
|
||
|
guile mode for the first time, it gets a Scheme representation and is
|
||
|
listed by <code class="code">all-threads</code>, for example.
|
||
|
</p>
|
||
|
<p>Threads in guile mode can block (e.g., do blocking I/O) without causing
|
||
|
any problems<a class="footnote" id="DOCF5" href="#FOOT5"><sup>5</sup></a>; temporarily leaving guile mode with
|
||
|
<code class="code">scm_without_guile</code> before blocking slightly improves GC
|
||
|
performance, though. For some common blocking operations, Guile
|
||
|
provides convenience functions. For example, if you want to lock a
|
||
|
pthread mutex while in guile mode, you might want to use
|
||
|
<code class="code">scm_pthread_mutex_lock</code> which is just like
|
||
|
<code class="code">pthread_mutex_lock</code> except that it leaves guile mode while
|
||
|
blocking.
|
||
|
</p>
|
||
|
|
||
|
<p>All libguile functions are (intended to be) robust in the face of
|
||
|
multiple threads using them concurrently. This means that there is no
|
||
|
risk of the internal data structures of libguile becoming corrupted in
|
||
|
such a way that the process crashes.
|
||
|
</p>
|
||
|
<p>A program might still produce nonsensical results, though. Taking
|
||
|
hashtables as an example, Guile guarantees that you can use them from
|
||
|
multiple threads concurrently and a hashtable will always remain a valid
|
||
|
hashtable and Guile will not crash when you access it. It does not
|
||
|
guarantee, however, that inserting into it concurrently from two threads
|
||
|
will give useful results: only one insertion might actually happen, none
|
||
|
might happen, or the table might in general be modified in a totally
|
||
|
arbitrary manner. (It will still be a valid hashtable, but not the one
|
||
|
that you might have expected.) Guile might also signal an error when it
|
||
|
detects a harmful race condition.
|
||
|
</p>
|
||
|
<p>Thus, you need to put in additional synchronizations when multiple
|
||
|
threads want to use a single hashtable, or any other mutable Scheme
|
||
|
object.
|
||
|
</p>
|
||
|
<p>When writing C code for use with libguile, you should try to make it
|
||
|
robust as well. An example that converts a list into a vector will help
|
||
|
to illustrate. Here is a correct version:
|
||
|
</p>
|
||
|
<div class="example">
|
||
|
<pre class="example-preformatted">SCM
|
||
|
my_list_to_vector (SCM list)
|
||
|
{
|
||
|
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
|
||
|
size_t len, i;
|
||
|
|
||
|
len = scm_c_vector_length (vector);
|
||
|
i = 0;
|
||
|
while (i < len && scm_is_pair (list))
|
||
|
{
|
||
|
scm_c_vector_set_x (vector, i, scm_car (list));
|
||
|
list = scm_cdr (list);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return vector;
|
||
|
}
|
||
|
</pre></div>
|
||
|
|
||
|
<p>The first thing to note is that storing into a <code class="code">SCM</code> location
|
||
|
concurrently from multiple threads is guaranteed to be robust: you don’t
|
||
|
know which value wins but it will in any case be a valid <code class="code">SCM</code>
|
||
|
value.
|
||
|
</p>
|
||
|
<p>But there is no guarantee that the list referenced by <var class="var">list</var> is not
|
||
|
modified in another thread while the loop iterates over it. Thus, while
|
||
|
copying its elements into the vector, the list might get longer or
|
||
|
shorter. For this reason, the loop must check both that it doesn’t
|
||
|
overrun the vector and that it doesn’t overrun the list. Otherwise,
|
||
|
<code class="code">scm_c_vector_set_x</code> would raise an error if the index is out of
|
||
|
range, and <code class="code">scm_car</code> and <code class="code">scm_cdr</code> would raise an error if the
|
||
|
value is not a pair.
|
||
|
</p>
|
||
|
<p>It is safe to use <code class="code">scm_car</code> and <code class="code">scm_cdr</code> on the local
|
||
|
variable <var class="var">list</var> once it is known that the variable contains a pair.
|
||
|
The contents of the pair might change spontaneously, but it will always
|
||
|
stay a valid pair (and a local variable will of course not spontaneously
|
||
|
point to a different Scheme object).
|
||
|
</p>
|
||
|
<p>Likewise, a vector such as the one returned by <code class="code">scm_make_vector</code> is
|
||
|
guaranteed to always stay the same length so that it is safe to only use
|
||
|
scm_c_vector_length once and store the result. (In the example,
|
||
|
<var class="var">vector</var> is safe anyway since it is a fresh object that no other
|
||
|
thread can possibly know about until it is returned from
|
||
|
<code class="code">my_list_to_vector</code>.)
|
||
|
</p>
|
||
|
<p>Of course the behavior of <code class="code">my_list_to_vector</code> is suboptimal when
|
||
|
<var class="var">list</var> does indeed get asynchronously lengthened or shortened in
|
||
|
another thread. But it is robust: it will always return a valid vector.
|
||
|
That vector might be shorter than expected, or its last elements might
|
||
|
be unspecified, but it is a valid vector and if a program wants to rule
|
||
|
out these cases, it must avoid modifying the list asynchronously.
|
||
|
</p>
|
||
|
<p>Here is another version that is also correct:
|
||
|
</p>
|
||
|
<div class="example">
|
||
|
<pre class="example-preformatted">SCM
|
||
|
my_pedantic_list_to_vector (SCM list)
|
||
|
{
|
||
|
SCM vector = scm_make_vector (scm_length (list), SCM_UNDEFINED);
|
||
|
size_t len, i;
|
||
|
|
||
|
len = scm_c_vector_length (vector);
|
||
|
i = 0;
|
||
|
while (i < len)
|
||
|
{
|
||
|
scm_c_vector_set_x (vector, i, scm_car (list));
|
||
|
list = scm_cdr (list);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return vector;
|
||
|
}
|
||
|
</pre></div>
|
||
|
|
||
|
<p>This version relies on the error-checking behavior of <code class="code">scm_car</code> and
|
||
|
<code class="code">scm_cdr</code>. When the list is shortened (that is, when <var class="var">list</var>
|
||
|
holds a non-pair), <code class="code">scm_car</code> will throw an error. This might be
|
||
|
preferable to just returning a half-initialized vector.
|
||
|
</p>
|
||
|
<p>The API for accessing vectors and arrays of various kinds from C takes a
|
||
|
slightly different approach to thread-robustness. In order to get at
|
||
|
the raw memory that stores the elements of an array, you need to
|
||
|
<em class="emph">reserve</em> that array as long as you need the raw memory. During
|
||
|
the time an array is reserved, its elements can still spontaneously
|
||
|
change their values, but the memory itself and other things like the
|
||
|
size of the array are guaranteed to stay fixed. Any operation that
|
||
|
would change these parameters of an array that is currently reserved
|
||
|
will signal an error. In order to avoid these errors, a program should
|
||
|
of course put suitable synchronization mechanisms in place. As you can
|
||
|
see, Guile itself is again only concerned about robustness, not about
|
||
|
correctness: without proper synchronization, your program will likely
|
||
|
not be correct, but the worst consequence is an error message.
|
||
|
</p>
|
||
|
<p>Real thread-safety often requires that a critical section of code is
|
||
|
executed in a certain restricted manner. A common requirement is that
|
||
|
the code section is not entered a second time when it is already being
|
||
|
executed. Locking a mutex while in that section ensures that no other
|
||
|
thread will start executing it, blocking asyncs ensures that no
|
||
|
asynchronous code enters the section again from the current thread, and
|
||
|
the error checking of Guile mutexes guarantees that an error is
|
||
|
signaled when the current thread accidentally reenters the critical
|
||
|
section via recursive function calls.
|
||
|
</p>
|
||
|
<p>Guile provides two mechanisms to support critical sections as outlined
|
||
|
above. You can either use the macros
|
||
|
<code class="code">SCM_CRITICAL_SECTION_START</code> and <code class="code">SCM_CRITICAL_SECTION_END</code>
|
||
|
for very simple sections; or use a dynwind context together with a
|
||
|
call to <code class="code">scm_dynwind_critical_section</code>.
|
||
|
</p>
|
||
|
<p>The macros only work reliably for critical sections that are
|
||
|
guaranteed to not cause a non-local exit. They also do not detect an
|
||
|
accidental reentry by the current thread. Thus, you should probably
|
||
|
only use them to delimit critical sections that do not contain calls
|
||
|
to libguile functions or to other external functions that might do
|
||
|
complicated things.
|
||
|
</p>
|
||
|
<p>The function <code class="code">scm_dynwind_critical_section</code>, on the other hand,
|
||
|
will correctly deal with non-local exits because it requires a dynwind
|
||
|
context. Also, by using a separate mutex for each critical section,
|
||
|
it can detect accidental reentries.
|
||
|
</p>
|
||
|
</div>
|
||
|
<div class="footnotes-segment">
|
||
|
<hr>
|
||
|
<h4 class="footnotes-heading">Footnotes</h4>
|
||
|
|
||
|
<h5 class="footnote-body-heading"><a id="FOOT5" href="#DOCF5">(5)</a></h5>
|
||
|
<p>In Guile 1.8, a thread blocking in guile mode
|
||
|
would prevent garbage collection to occur. Thus, threads had to leave
|
||
|
guile mode whenever they could block. This is no longer needed with
|
||
|
Guile 2.<var class="var">x</var>.</p>
|
||
|
</div>
|
||
|
<hr>
|
||
|
<div class="nav-panel">
|
||
|
<p>
|
||
|
Previous: <a href="Asynchronous-Signals.html">Asynchronous Signals</a>, Up: <a href="General-Libguile-Concepts.html">General concepts for using libguile</a> [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html" title="Index" rel="index">Index</a>]</p>
|
||
|
</div>
|
||
|
|
||
|
|
||
|
|
||
|
</body>
|
||
|
</html>
|