start some notes on threading

This commit is contained in:
John Cupitt 2015-04-27 10:57:27 +01:00
parent ffdd9ff851
commit f5a77dd80d
6 changed files with 204 additions and 3 deletions

View File

@ -1,6 +1,7 @@
25/4/15 started 8.0.1
- fix some compiler warnings
- work around a glib bug that can cause segv under load
- add some notes on threading to the docs
11/2/15 started 8.0
- remove old doc stuff, lots of doc improvements

View File

@ -133,6 +133,7 @@ HTML_IMAGES = \
content_files = \
using-command-line.xml \
using-C.xml \
using-threads.xml \
using-python.xml \
using-cpp.xml \
extending.xml \
@ -146,6 +147,7 @@ content_files = \
expand_content_files = \
using-command-line.xml \
using-C.xml \
using-threads.xml \
using-python.xml \
using-cpp.xml \
extending.xml \

View File

@ -9,7 +9,7 @@
<bookinfo>
<title>VIPS Reference Manual</title>
<releaseinfo>
For VIPS 8.0.0.
For VIPS 8.0.1.
The latest version of this documentation can be found on the
<ulink role="online-location"
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
@ -38,6 +38,7 @@
<xi:include href="xml/extending.xml"/>
<xi:include href="xml/function-list.xml"/>
<xi:include href="xml/file-format.xml"/>
<xi:include href="xml/using-threads.xml"/>
</chapter>
<chapter>

View File

@ -38,6 +38,7 @@
<xi:include href="xml/extending.xml"/>
<xi:include href="xml/function-list.xml"/>
<xi:include href="xml/file-format.xml"/>
<xi:include href="xml/using-threads.xml"/>
</chapter>
<chapter>

196
doc/using-threads.xml Normal file
View File

@ -0,0 +1,196 @@
<?xml version="1.0"?>
<!-- vim: set ts=2 sw=2 expandtab: -->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
]>
<refentry id="using-threads">
<refmeta>
<refentrytitle>VIPS and threads</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>VIPS Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Using VIPS</refname>
<refpurpose>VIPS and threading</refpurpose>
</refnamediv>
<refsect3 id="using-threads-intro">
<title>Introduction</title>
<para>
This section tries to summarise the rules for threaded programs using
libvips. Generally, libvips is threaded and thread-safe, with a few
exceptions.
</para>
</refsect3>
<refsect3 id="using-threads-images">
<title>Images</title>
<para>
On startup, you need to call VIPS_INIT() single-threaded. After that,
you can freely create images in any thread and read them in any other
thread. See the example at the end of this chapter.
Note that results can also be shared between threads for you by the vips
operation cache.
</para>
<para>
When libvips calculates an image, by default it will use as many
threads as you have CPU cores. Use vips_concurrency_set() to change this.
</para>
<para>
The exception is the drawing operators, such as vips_draw_circle().
These operations modify their image argument, so you can't call them on
the same image from more than one thread. Reading from an iamge while
another thread is writing to it with one of the draw operations will
obviously also fail.
</para>
</refsect3>
<refsect3 id="using-threads-errors">
<title>Error handling</title>
<para>
</para>
</refsect3>
<refsect3 id="using-threads-regions">
<title>Using #VipsRegion between threads</title>
<para>
</para>
</refsect3>
<refsect3 id="using-threads-example">
<title>Example</title>
<example>
<title>VIPS and threads example</title>
<programlisting language="C">
/* Read from many threads.
*
* Compile with:
*
* gcc -g -Wall soak.c `pkg-config vips --cflags --libs`
*
* Run with:
*
* rm -rf x
* mkdir x
* for i in {0..10}; do ./a.out ~/pics/k2.jpg; done
*
*/
#include &lt;stdio.h&gt;
#include &lt;glib.h&gt;
#include &lt;vips/vips.h&gt;
/* How many pings we run at once.
*/
#define NUM_IN_PARALLEL (50)
/* Number of tests we do in total.
*/
#define TOTAL_TESTS (NUM_IN_PARALLEL * 20)
/* Workers queue up on this.
*/
GMutex allocation_lock;
/* Our set of threads.
*/
GThread *workers[NUM_IN_PARALLEL];
/* Number of calls so far.
*/
int n_calls = 0;
/* Our test function. This is called by NUM_IN_PARALLEL threads a total of
* TOTAL_TESTS times.
*/
static int
test (const char *filename)
{
VipsImage *im, *x;
char output_file[256];
snprintf (output_file, 256, "x/tmp-%p.jpg", g_thread_self ());
if (!(im = vips_image_new_from_file (filename,
"access",
VIPS_ACCESS_SEQUENTIAL_UNBUFFERED,
NULL)))
return (-1);
if (vips_resize (im, &amp;x, 0.1, NULL))
{
g_object_unref (im);
return (-1);
}
g_object_unref (im);
im = x;
if (vips_image_write_to_file (im, output_file, NULL))
{
g_object_unref (im);
return (-1);
}
g_object_unref (im);
return (0);
}
/* What we run as a thread.
*/
static void *
worker (void *data)
{
const char *filename = (const char *) data;
for (;;)
{
gboolean done;
done = FALSE;
g_mutex_lock (&amp;allocation_lock);
n_calls += 1;
if (n_calls &gt; TOTAL_TESTS)
done = TRUE;
g_mutex_unlock (&amp;allocation_lock);
if (done)
break;
if (test (filename))
vips_error_exit (NULL);
}
return (NULL);
}
int
main (int argc, char **argv)
{
int i;
if (VIPS_INIT (argv[0]))
vips_error_exit (NULL);
g_mutex_init (&amp;allocation_lock);
for (i = 0; i &lt; NUM_IN_PARALLEL; i++)
workers[i] = g_thread_new (NULL, (GThreadFunc) worker, argv[1]);
for (i = 0; i &lt; NUM_IN_PARALLEL; i++)
g_thread_join (workers[i]);
return (0);
}
</programlisting>
</example>
</refsect3>
</refentry>

View File

@ -216,8 +216,8 @@ vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data )
* #VipsThreadPool.
*
* The special value 0 means "default". In this case, the number of threads is
* set by the environmnt variable VIPS_CONCURRENCY, or if that is not set, the
* number of threads availble on the hist machine.
* set by the environment variable VIPS_CONCURRENCY, or if that is not set, the
* number of threads availble on the host machine.
*
* See also: vips_concurrency_get().
*/