improve thread-safety

the cache and link thing now lock, so you can create images and process
them from several threads
This commit is contained in:
John Cupitt 2012-07-07 18:37:47 +01:00
parent 57492bee16
commit cff8f44373
3 changed files with 37 additions and 6 deletions

View File

@ -2,6 +2,8 @@
*
* 20/6/12
* - try to make it compile on centos5
* 7/7/12
* - add a lock so we can run operations from many threads
*/
/*
@ -103,6 +105,10 @@ static GHashTable *vips_cache_table = NULL;
*/
static int vips_cache_time = 0;
/* Protect cache access with this.
*/
static GMutex *vips_cache_lock = NULL;
/* Old versions of glib are missing these. When we abandon centos 5, switch to
* g_int64_hash() and g_double_hash().
*/
@ -407,6 +413,8 @@ static void
vips_cache_init( void )
{
if( !vips_cache_table ) {
vips_cache_lock = g_mutex_new();
vips_cache_table = g_hash_table_new(
(GHashFunc) vips_operation_hash,
(GEqualFunc) vips_operation_equal );
@ -438,7 +446,6 @@ vips_cache_print_fn( void *value, void *a, void *b )
return( NULL );
}
/**
* vips_cache_print:
*
@ -447,11 +454,15 @@ vips_cache_print_fn( void *value, void *a, void *b )
void
vips_cache_print( void )
{
g_mutex_lock( vips_cache_lock );
if( vips_cache_table ) {
printf( "Operation cache:\n" );
vips_hash_table_map( vips_cache_table,
vips_cache_print_fn, NULL, NULL );
}
g_mutex_unlock( vips_cache_lock );
}
static void *
@ -578,6 +589,8 @@ vips_cache_trim( void )
{
VipsOperation *operation;
g_mutex_lock( vips_cache_lock );
while( vips_cache_table &&
(g_hash_table_size( vips_cache_table ) > vips_cache_max ||
vips_tracked_get_files() > vips_cache_max_files ||
@ -589,6 +602,8 @@ vips_cache_trim( void )
vips_cache_drop( operation );
}
g_mutex_unlock( vips_cache_lock );
}
static void *
@ -659,6 +674,8 @@ vips_cache_operation_buildp( VipsOperation **operation )
vips_cache_trim();
g_mutex_lock( vips_cache_lock );
if( (hit = g_hash_table_lookup( vips_cache_table, *operation )) ) {
if( vips__cache_trace ) {
printf( "vips cache: hit %p\n ", hit );
@ -672,7 +689,10 @@ vips_cache_operation_buildp( VipsOperation **operation )
*operation = hit;
}
else {
g_mutex_unlock( vips_cache_lock );
if( !hit ) {
if( vips__cache_trace ) {
if( (*operation)->nocache )
printf( "vips cache: uncacheable %p\n ",
@ -682,16 +702,21 @@ vips_cache_operation_buildp( VipsOperation **operation )
vips_object_print_summary( VIPS_OBJECT( *operation ) );
}
if( vips_object_build( VIPS_OBJECT( *operation ) ) )
if( vips_object_build( VIPS_OBJECT( *operation ) ) )
return( -1 );
g_mutex_lock( vips_cache_lock );
if( !(*operation)->nocache ) {
vips_cache_ref( *operation );
g_hash_table_insert( vips_cache_table,
*operation, *operation );
}
g_mutex_unlock( vips_cache_lock );
}
return( 0 );
}

View File

@ -50,6 +50,9 @@
* 24/3/11
* - move demand_hint stuff in here
* - move to vips_ namespace
* 7/7/12
* - lock around link make/break so we can process an image from many
* threads
*/
/*
@ -172,10 +175,12 @@ vips__link_break_rev( VipsImage *image_down, VipsImage *image_up )
void
vips__link_break_all( VipsImage *image )
{
g_mutex_lock( vips__global_lock );
vips_slist_map2( image->upstream,
(VipsSListMap2Fn) vips__link_break, image, NULL );
vips_slist_map2( image->downstream,
(VipsSListMap2Fn) vips__link_break_rev, image, NULL );
g_mutex_unlock( vips__global_lock );
g_assert( !image->upstream );
g_assert( !image->downstream );
@ -326,8 +331,10 @@ vips_demand_hint_array( VipsImage *image, VipsDemandStyle hint, VipsImage **in )
/* im depends on all these ims.
*/
g_mutex_lock( vips__global_lock );
for( i = 0; i < len; i++ )
vips__link_make( in[i], image );
g_mutex_unlock( vips__global_lock );
/* Set a flag on the image to say we remembered to call this thing.
* vips_image_generate() and friends check this.

View File

@ -835,9 +835,8 @@ vips_threadpool_create_threads( VipsThreadpool *pool )
* processed, @progress is called, so that the operation can give
* progress feedback. @progress may be %NULL.
*
* Each thread has private state that the @allocate and @work functions can
* use to communicate. This state is created by each worker as it starts using
* @start. Use the state destructor to clean up.
* The object returned by @start must be an instance of a subclass of
* #VipsThreadState. Use this to communicate between @allocate and @work.
*
* @allocate and @start are always single-threaded (so they can write to the
* per-pool state), whereas @work can be executed concurrently. @progress is