diff --git a/doc/using-threads.xml b/doc/using-threads.xml index 7ffe3880..b00c6e79 100644 --- a/doc/using-threads.xml +++ b/doc/using-threads.xml @@ -35,16 +35,16 @@ - 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. + 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 image while + another thread is writing to it with one of the draw operations will + obviously also fail. - 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. + 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. @@ -52,6 +52,24 @@ Error handling + libvips has a single error code (-1 or %NULL) returned by all functions + on error. Error messages are not returned, instead they are logged + in a single global error buffer shared by all threads, see + vips_error_buffer(). + + + + This makes error handling very simple but the obvious downside is that + because error returns and error messages are separate when you + detect an error return you can't be + sure that what's in the error buffer is the message that matches your + error. + + + + The simplest way to handle this is to present the whole error log to + the user on the next interaction and leave it to them to decide what + action caused the failure. @@ -59,11 +77,35 @@ Using #VipsRegion between threads + #VipsImage objects are immutable and can be shared between + threads very simply. + However the lower-level #VipsRegion object used to implement #VipsImage + (see Extending VIPS) is mutable and you + can only use a #VipsRegion from one thread at once. + + + In fact it's worse than that: to reduce locking, #VipsRegion keeps a + lot of state in per-thread storage. If you want to create a region in + one thread and use it in another, you have to first tag the region as + unowned from the creating thread with vips__region_no_ownership(), then + in the recieving thread take ownership with + vips__region_take_ownership(). See the source for operations like + vips_tilecache() if you're curious how this works. + + + + libvips includes a set of sanity checks for region ownership and will + fail if you don't pass ownership correctly. + + Example + + This example runs many vips_resize() in parallel from many threads. + VIPS and threads example