5.5 Cloning

The context contains the exception stack for the fz_try/fz_catch constructs. As such trying to use the same context from multiple threads at the same time will lead to crashes.

The solution to this is to ‘clone’ the context. Each clone will share the same underlying store (and will inherit the same settings, such as allocators, locks etc), but will have its own exception stack. Other settings, such as anti-alias levels, will be inherited from the original at the time of cloning, but can be changed to be different if required.

For example, in a viewer application, we might want to have a background process that runs through the file generating page thumbnails. In order for this not to interfere with the foreground process, we would clone the context, and use the cloned context in the thumbnailing thread. We might choose to disable anti-aliasing for the thumbnailing thread to trade quality for speed.

Any images decoded for the thumbnailing thread would live on in the store though, and would hence be available should the viewers normal render operations need them.

To clone a context, use fz_clone_context:

/* 
   fz_clone_context: Make a clone of an existing context. 
 
   This function is meant to be used in multi-threaded 
   applications where each thread requires its own context, yet 
   parts of the global state, for example caching, are shared. 
 
   ctx: Context obtained from fz_new_context to make a copy of. 
   ctx must have had locks and lock/functions setup when created. 
   The two contexts will share the memory allocator, resource 
   store, locks and lock/unlock functions. They will each have 
   their own exception stacks though. 
 
   Does not throw exception, but may return NULL. 
*/ 
fz_context *fz_clone_context(fz_context *ctx);

For example:

fz_context *worker_ctx = fz_clone_context(ctx);

In order for cloned contexts to work safely, they rely on being able to take locks around certain operations to make them atomic. Accordingly, fz_clone_context will return NULL (to indicate failure) if the base context did not have locking functions defined.