Thread-safe implementation of the direct bindings

This module is an implementation of general interface anatomist.base. It is based on direct implementation (bindings of C++ Anatomist api) with adding thread-safe layer.

This implementation can be used in multi-threaded application. To load it, you can do :

>>> import anatomist
>>> anatomist.setDefaultImplementation(anatomist.THREADED)
>>> import anatomist.api as anatomist

or without changing default implementation :

>>> import anatomist.threaded.api as anatomist

This module redefines the Anatomist class from the direct implementation Anatomist class to make all methods execute in the main thread (qt thread). It uses methods of anatomist.threadedimpl.

Note that this thread-safe implementation is not actually multi-threaded: all calls to the Anatomist API are stacked for execution in the same thread, so it is actually a single-thread execution, but calls can be performed from various threads in a multi-threaded program, avoiding race conditions (provided the calling thread has not locked the main thread in any way).

All classes in the anatomist module are made thread-safe.

Objects returned by calls to the thread-safe API

Generally, objects created (or just returned) by calls to the Anatomist thread-safe API belong to the main thread. This means that they must be used, and importantly, destroyed, within the main thread.

Using objects

When returned objects are classes from the Anatomist API, they are subclasses of the thread-safe API, and are already made thread-safe when used.

When objects do not belong to the Anatomist API, like Qt widgets, then caution must be taken to use them from the main GUI thread only. You can use soma.qt_gui.qtThread.QtThreadCall to do so.

Destroying objects

Destruction of objects in python is somewhat tricky: when a variable is deleted, a reference to it is decremented, and when the last reference is dropped, the object is actually destroyed, indeed from the thread removing this last reference. If several threads hold a reference to a given object, who will actually delete it ? If a sensible (non-thread-safe) object is deleted within the wrong thread, program crashes may occur.

To manage this problem we use wrapper objects which will delegate the destruction of objects they contain to the main thread: soma.qt_gui.qtThread.MainThreadLife.

AItem subclasses in the threaded implementation (including AObject, AWindow etc) are already subclasses of MainThreadLife.

Utility sub-module for the threaded implementation

This module makes anatomist module given implementation thread safe.

The ThreadSafeMetaclass is used to build thread-safe versions of classes (Anatomist, AItem and other inherited classes).

The function getThreadSafeClass() enables to create a thread safe class based on a given Anatomist implementation class. It replaces all methods by a call in main thread of the same method. The ThreadSafeMetaclass metaclass ensures that inherited classes will also be thread safe.

class anatomist.threadedimpl.ThreadSafeMetaclass(name, bases, attdict)[source]

The ThreadSafeMetaclass replaces all methods of the classes it builds with thread-safe wrappers. All function calls are actually deported to the main thread. Subclasses are also handled. Anatomist.AItem is also made to inherit soma.qt_gui.qtThread.MainThreadLife and makes a hook to force deletion to happen in the main thread when reference count reaches zero from any thread.

This meta-class inherits from the meta-class used by PyQt classes.

anatomist.threadedimpl.getThreadSafeClass(classObj, mainThread)[source]

Generates a thread safe class which inherits from the class given in parameters. Methods are executed in the main thread to be thread safe.

Parameters:
  • classObj (Class) – the class which needs to be thread safe
  • mainThread (QtThreadCall) – an object that enables to send tasks to the main thread.
Returns:

new_class – The generated thread safe class

Return type:

Class

anatomist.threadedimpl.get_thead_safe_dict(cls, dictatt, filtered=False)[source]

Builds thread-safe wrappers around dict elements which are methods or functions, replace classes by thread-safe subclasses. Methods are actually queried on the class cls through its __mro__

anatomist.threadedimpl.threadSafeCall(mainThread, func)[source]

Utility function wrapper for main thread calls

Returns:func – a function that sends the given function’s call to the main thread
Return type:function
anatomist.threadedimpl.threadedModule(anatomistModule, mainThread=None)[source]

Adds to current module a thread safe version of given anatomist module, replacing Anatomist class by thread safe Anatomist class.

Parameters:
  • anatomistModule (module) – a module containing an implementation of Anatomist class
  • mainThread (MainThreadActions (optional)) – an object that enables to send tasks to the mainThread. If it is not given in parameters, an instance will be created in this function. So it must be called by the mainThread.