Hardware Locality (hwloc): Thread Safety

Hardware Locality (hwloc) 2.9.0

Thread Safety

Like most libraries that mainly fill data structures, hwloc is not thread safe but rather reentrant: all state is held in a hwloc_topology_t instance without mutex protection. That means, for example, that two threads can safely operate on and modify two different hwloc_topology_t instances, but they should not simultaneously invoke functions that modify the same instance. Similarly, one thread should not modify a hwloc_topology_t instance while another thread is reading or traversing it. However, two threads can safely read or traverse the same hwloc_topology_t instance concurrently.

When running in multiprocessor environments, be aware that proper thread synchronization and/or memory coherency protection is needed to pass hwloc data (such as hwloc_topology_t pointers) from one processor to another (e.g., a mutex, semaphore, or a memory barrier). Note that this is not a hwloc-specific requirement, but it is worth mentioning.

For reference, hwloc_topology_t modification operations include (but may not be limited to):

Creation and destruction

  `hwloc_topology_init(), hwloc_topology_load(), hwloc_topology_destroy()` (see Topology Creation and Destruction) imply major modifications of the structure, including freeing some objects. No other thread cannot access the topology or any of its objects at the same time.

  Also references to objects inside the topology are not valid anymore after these functions return.

Runtime topology modifications

  `hwloc_topology_insert_misc_object()`, `hwloc_topology_alloc_group_object()`, and `hwloc_topology_insert_group_object()` (see Modifying a loaded Topology) may modify the topology significantly by adding objects inside the tree, changing the topology depth, etc.

  `hwloc_distances_add_commit()` and `hwloc_distances_remove()` (see Add distances between objects) modify the list of distance structures in the topology, and the former may even insert new Group objects.

  `hwloc_memattr_register()` and `hwloc_memattr_set_value()` (see Managing memory attributes) modify the memory attributes of the topology.

  `hwloc_topology_restrict()` modifies the topology even more dramatically by removing some objects.

  `hwloc_topology_refresh()` updates some internal cached structures. (see below).

  Although references to former objects may still be valid after insertion or restriction, it is strongly advised to not rely on any such guarantee and always re-consult the topology to reacquire new instances of objects.

Consulting distances

  `hwloc_distances_get()` and its variants are thread-safe except if the topology was recently modified (because distances may involve objects that were removed).

  Whenever the topology is modified (see above), `hwloc_topology_refresh()` should be called in the same thread-safe context to force the refresh of internal distances structures. A call to `hwloc_distances_get()` may also refresh distances-related structures.

  Once this refresh has been performed, multiple `hwloc_distances_get()` may then be performed concurrently by multiple threads.

Consulting memory attributes

  Functions consulting memory attributes in hwloc/memattrs.h are thread-safe except if the topology was recently modified (because memory attributes may involve objects that were removed).

  Whenever the topology is modified (see above), `hwloc_topology_refresh()` should be called in the same thread-safe context to force the refresh of internal memory attribute structures. A call to `hwloc_memattr_get_value()` or `hwloc_memattr_get_targets()` may also refresh internal structures for a given memory attribute.

  Once this refresh has been performed, multiple functions consulting memory attributes may then be performed concurrently by multiple threads.

Locating topologies

  `hwloc_topology_set_*` (see Topology Detection Configuration and Query) do not modify the topology directly, but they do modify internal structures describing the behavior of the upcoming invocation of `hwloc_topology_load()`. Hence, all of these functions should not be used concurrently.