start some notes on threading
This commit is contained in:
parent
ffdd9ff851
commit
f5a77dd80d
@ -1,6 +1,7 @@
|
|||||||
25/4/15 started 8.0.1
|
25/4/15 started 8.0.1
|
||||||
- fix some compiler warnings
|
- fix some compiler warnings
|
||||||
- work around a glib bug that can cause segv under load
|
- 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
|
11/2/15 started 8.0
|
||||||
- remove old doc stuff, lots of doc improvements
|
- remove old doc stuff, lots of doc improvements
|
||||||
|
@ -133,6 +133,7 @@ HTML_IMAGES = \
|
|||||||
content_files = \
|
content_files = \
|
||||||
using-command-line.xml \
|
using-command-line.xml \
|
||||||
using-C.xml \
|
using-C.xml \
|
||||||
|
using-threads.xml \
|
||||||
using-python.xml \
|
using-python.xml \
|
||||||
using-cpp.xml \
|
using-cpp.xml \
|
||||||
extending.xml \
|
extending.xml \
|
||||||
@ -146,6 +147,7 @@ content_files = \
|
|||||||
expand_content_files = \
|
expand_content_files = \
|
||||||
using-command-line.xml \
|
using-command-line.xml \
|
||||||
using-C.xml \
|
using-C.xml \
|
||||||
|
using-threads.xml \
|
||||||
using-python.xml \
|
using-python.xml \
|
||||||
using-cpp.xml \
|
using-cpp.xml \
|
||||||
extending.xml \
|
extending.xml \
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<bookinfo>
|
<bookinfo>
|
||||||
<title>VIPS Reference Manual</title>
|
<title>VIPS Reference Manual</title>
|
||||||
<releaseinfo>
|
<releaseinfo>
|
||||||
For VIPS 8.0.0.
|
For VIPS 8.0.1.
|
||||||
The latest version of this documentation can be found on the
|
The latest version of this documentation can be found on the
|
||||||
<ulink role="online-location"
|
<ulink role="online-location"
|
||||||
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
|
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/extending.xml"/>
|
||||||
<xi:include href="xml/function-list.xml"/>
|
<xi:include href="xml/function-list.xml"/>
|
||||||
<xi:include href="xml/file-format.xml"/>
|
<xi:include href="xml/file-format.xml"/>
|
||||||
|
<xi:include href="xml/using-threads.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter>
|
<chapter>
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<xi:include href="xml/extending.xml"/>
|
<xi:include href="xml/extending.xml"/>
|
||||||
<xi:include href="xml/function-list.xml"/>
|
<xi:include href="xml/function-list.xml"/>
|
||||||
<xi:include href="xml/file-format.xml"/>
|
<xi:include href="xml/file-format.xml"/>
|
||||||
|
<xi:include href="xml/using-threads.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
<chapter>
|
<chapter>
|
||||||
|
196
doc/using-threads.xml
Normal file
196
doc/using-threads.xml
Normal 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 <stdio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
/* 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, &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 (&allocation_lock);
|
||||||
|
n_calls += 1;
|
||||||
|
if (n_calls > TOTAL_TESTS)
|
||||||
|
done = TRUE;
|
||||||
|
g_mutex_unlock (&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 (&allocation_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_IN_PARALLEL; i++)
|
||||||
|
workers[i] = g_thread_new (NULL, (GThreadFunc) worker, argv[1]);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_IN_PARALLEL; i++)
|
||||||
|
g_thread_join (workers[i]);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
</programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
</refsect3>
|
||||||
|
|
||||||
|
</refentry>
|
@ -216,8 +216,8 @@ vips_g_thread_new( const char *domain, GThreadFunc func, gpointer data )
|
|||||||
* #VipsThreadPool.
|
* #VipsThreadPool.
|
||||||
*
|
*
|
||||||
* The special value 0 means "default". In this case, the number of threads is
|
* 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
|
* set by the environment variable VIPS_CONCURRENCY, or if that is not set, the
|
||||||
* number of threads availble on the hist machine.
|
* number of threads availble on the host machine.
|
||||||
*
|
*
|
||||||
* See also: vips_concurrency_get().
|
* See also: vips_concurrency_get().
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user