1.5.8 Management of locks in multithreaded applications

A thread-safe function protects shared resources from concurrent access using locks. There are functions in the C library that you can re-implement, that enable you to manage the locking mechanisms and so prevent the corruption of shared data such as the heap.

These functions are mutex functions, where the lifecycle of a mutex is one of initialization, iterative acquisition and releasing of the mutex as required, and then optionally freeing the mutex when it is never going to be required again. The mutex functions wrap onto your own Real-Time Operating System (RTOS) calls, and their function prototypes are:

_mutex_initialize()

int _mutex_initialize(mutex *m);

This function accepts a pointer to a 32-bit word and initializes it as a valid mutex.

By default, _mutex_initialize() returns zero for a nonthreaded application. Therefore, in a multithreaded application, _mutex_initialize() must return a nonzero value on success so that at runtime, the library knows that it is being used in a multithreaded environment.

Ensure that _mutex_initialize() initializes the mutex to an unlocked state.

This function must be supplied if you are using mutexes.

_mutex_acquire()

void _mutex_acquire(mutex *m);

This function causes the calling thread to obtain a lock on the supplied mutex.

_mutex_acquire() returns immediately if the mutex has no owner. If the mutex is owned by another thread, _mutex_acquire() must block until it becomes available.

_mutex_acquire() is not called by the thread that already owns the mutex.

This function must be supplied if you are using mutexes.

_mutex_release()

void _mutex_release(mutex *m);

This function causes the calling thread to release the lock on a mutex acquired by _mutex_acquire().

The mutex remains in existence, and can be re-locked by a subsequent call to mutex_acquire().

_mutex_release() assumes that the mutex is owned by the calling thread.

This function must be supplied if you are using mutexes.

_mutex_free()

void _mutex_free(mutex *m);

This function causes the calling thread to free the supplied mutex. Any operating system resources associated with the mutex are freed. The mutex is destroyed and cannot be reused.

_mutex_free() assumes that the mutex is owned by the calling thread.

This function is optional. If you do not supply this function, the C library does not attempt to call it.

The mutex data structure type that is used as the parameter to the _mutex_*() functions is not defined in any of the ARM® Compiler toolchain header files, but must be defined elsewhere. Typically, it is defined as part of RTOS code.

Functions that call _mutex_*() functions create 4 bytes of memory for holding the mutex data structure. __Heap_Initialize() is one such function.

For the C library, a mutex is specified as a single 32-bit word of memory that can be placed anywhere. However, if your mutex implementation requires more space than this, or demands that the mutex be in a special memory area, then you must treat the default mutex as a pointer to a real mutex.

A typical example of a re-implementation framework for _mutex_initialize(), _mutex_acquire(), and _mutex_release() is as follows, where SEMAPHORE_ID, CreateLock(), AcquireLock(), and ReleaseLock() are defined in the RTOS, and (...) implies additional parameters:

int _mutex_initialize(SEMAPHORE_ID *sid)
{
   /* Create a mutex semaphore */
    *sid = CreateLock(...);
    return 1;
}
void _mutex_acquire(SEMAPHORE_ID *sid)
{
    /* Task sleep until get semaphore */
    AcquireLock(*sid, ...);
}
void _mutex_release(SEMAPHORE_ID *sid)
{
    /* Release the semaphore. */
    ReleaseLock(*sid);
}
void _mutex_free(SEMAPHORE_ID *sid)
{
    /* Free the semaphore. */
    FreeLock(*sid, ...);
}

Note:

  • _mutex_release() releases the lock on the mutex that was acquired by _mutex_acquire(), but the mutex still exists, and can be re-locked by a subsequent call to _mutex_acquire().

  • It is only when the optional wrapper function _mutex_free() is called that the mutex is destroyed. After the mutex is destroyed, it cannot be used without first calling _mutex_initialize() to set it up again.

Non-ConfidentialPDF file icon PDF versionARM DUI0475M
Copyright © 2010-2016 ARM Limited or its affiliates. All rights reserved.