You copied the Doc URL to your clipboard.

Arm Compiler Arm C and C++ Libraries and Floating-Point Support User Guide : Thread-safe initialization of Mutexes and Condition variables [ALPHA]

Thread-safe initialization of Mutexes and Condition variables [ALPHA]

The Mutexes and Condition Variable parts of the porting API must adopt an initialize-on-first-use strategy. Implementations must ensure that such initializations are thread-safe.


This topic describes an [ALPHA] feature. See Support level definitions.

Consider the following sample implementation of the __ARM_TPL_mutex_lock() function:

// [1] Include the header for your operating system, which defines a 
// platform-specific API for mutexes. The names below were created for this
// example only.
#include <platform.h>

// Assume that platform.h declares the following types and functions:
// struct platform_mutex_t;
// platform_mutex_t *alloc_platform_mutex();
// void lock_platform_mutex(platform_mutex_t *p);
// void unlock_platform_mutex(platform_mutex_t *p);
// void destroy_platform_mutex(platform_mutex_t *p);

// [2] Include the Arm TPL header, which defines the functions that you must
// implement.
#include <arm-tpl.h>

// [3] Implement the Arm TPL functions according to the API that your operating
// system provides.

void __ARM_TPL_mutex_lock(__ARM_TPL_mutex_t* __m) {
	if (__m->data == 0) {
		__m->data = static_cast<uintptr_t>(alloc_platform_mutex());

The anatomy of this snippet can be understood as follows:

  1. Assume the underlying system (included through platform.h) provides the type __platform_mutex_t and the functions alloc_platform_mutex(), lock_platform_mutex(), unlock_platform_mutex(), and destroy_platform_mutex().
  2. The porting API header (arm-tpl.h) is then included, which defines the type __ARM_TPL_mutex_t and the prototypes for the various porting API functions.
  3. The implementations of the various porting API functions follow.

This implementation of __ARM_TPL_mutex_lock() method leads to a race condition if multiple threads attempt to lock the same std::mutex object. Therefore, an implementation must ensure that __m->data initializes atomically. The following sections illustrate possible solutions to this problem.

Global locking

An implementation may employ a platform provided mutex to guard the initialization of *__m as follows:

static platform_mutex_t guard_mut;
void __ARM_TPL_mutex_lock(__ARM_TPL_mutex_t* __m) {
	volatile __ARM_TPL_mutex_t *__vm = __m;
	if (__vm->data == 0) {
		if (__vm->data == 0)
			__vm->data = static_cast<uintptr_t>(alloc_platform_mutex());


This solution could result in reduced performance because threads must contend for the shared mutex guard_mut for each initial std::mutex lock operation.

Lock free

An implementation avoiding global locking is achievable using the lock-free concurrency constructs available through the <stdatomic.h> header. The following snippet atomically attempts to initialize __m->data, and undo its attempt if another thread has already done the initialization:

#include <cstdint>
#include <stdatomic.h>

int __ARM_TPL_mutex_lock(__ARM_TPL_mutex_t *__m) {
	if (__m->data == 0){
		uintptr_t mut_new = reinterpret_cast<uintptr_t>(alloc_platform_mutex());
		uintptr_t mut_null = 0;
		if (!atomic_compare_exchange_strong(&__m->data, &mut_null, mut_new))
	return lock_platform_mutex(reinterpret_cast<platform_mutex_t*>(__m->data));

The Arm®v6‑M architecture does not support this method.

Was this page helpful? Yes No