|  | Home · Overviews · Examples |

# Implementing Atomic Operations

Qt uses an optimization called implicit sharing for many of its value classes.

Starting with Qt 4, all of Qt's implicitly shared classes can safely be copied across threads like any other value classes, i.e., they are fully reentrant. This is accomplished by implementing reference counting operations using atomic hardware instructions on all the different platforms supported by Qt.

To support a new architecture, it is important to ensure that these platform-specific atomic operations are implemented in a corresponding header file (`qatomic_ARCH.h`), and that this file is located in Qt's `src/corelib/arch` directory. For example, the Intel 80386 implementation is located in `src/corelib/arch/qatomic_i386.h`.

Currently, Qt assumes that the following operations have been implemented:

- int q_atomic_test_and_set_int()
- int q_atomic_test_and_set_acquire_int()
- int q_atomic_test_and_set_release_int()
- int q_atomic_test_and_set_ptr()
- int q_atomic_increment()
- int q_atomic_decrement()
- int q_atomic_set_int()
- int q_atomic_set_ptr()
- int q_atomic_fetch_and_add_int()
- int q_atomic_fetch_and_add_acquire_int()
- int q_atomic_fetch_and_add_release_int()

Note that these functions must be atomic with respect to both interrupts and multiple processors.

Warning: The functions mentioned in this document are used internally by Qt and are not part of the public API. They may change in future versions of Qt. The purpose of this document is to aid people interested in porting Qt to a new architecture.

### Member Documentation

#### int q_atomic_test_and_set_int (volatile int *ptr, int expected, int newval)

Atomic test-and-set for integers.

        if (*ptr == expected) {
            *ptr = newval;
            return !0;
        }
        return 0;

If the value in memory pointed to by ptr is the expected value, this function assigns newval to ptr and returns a non-zero value. If the value in memory pointed to by ptr is not the expected value, this function does nothing and returns zero.

There are 3 variants of the test-and-set integer function: Each variant implies a different memory semantic, i.e. the relation of memory operations before or after the test-and-set operation. Since modern hardware can reorder memory operations to improve performance, these functions are used to ensure the order of memory operations (often called a memory barrier).

Note: This variant of the test-and-set integer function implies that memory semantic is unspecified.

See also q_atomic_test_and_set_ptr().

#### int q_atomic_test_and_set_acquire_int (volatile int *ptr, int expected, int newval)

This function behaves essentially like the above function.

Note: This variant of the test-and-set integer function implies that the atomic test-and-set operation must be performed before memory operations after the test-and-set.

#### int q_atomic_test_and_set_release_int (volatile int *ptr, int expected, int newval)

This function behaves essentially like the above function.

Note: This variant of the test-and-set integer function implies that all memory operations must be performed before the test-and-set.

#### int q_atomic_test_and_set_ptr (volatile void *ptr, void *expected, void *newval)

Atomic test-and-set for pointers.

        if (*ptr == expected) {
            *ptr = newval;
            return !0;
        }
        return 0;

If the value in memory pointed to by ptr is the expected value, this function assigns newval to ptr and returns a non-zero value. If the value in memory pointed to by ptr is not the expected value, this function does nothing and returns zero.

See also q_atomic_test_and_set_int().

#### int q_atomic_increment (volatile int *ptr)

Atomic integer increment.

        ++(*ptr);
        return *ptr ? !0 : 0;

Increments the value in memory pointed to by ptr. This function returns zero if the new value of *ptr is zero; otherwise it returns a non-zero value.

Tip: Depending on the architecture, it may be easier to return the new value after incrementing *ptr:

        return ++(*ptr);

Another option is to return the zero-flag that is set by some processors in control or status registers:

        ++(*ptr);
        return !(ControlRegister & ZeroFlag);

See also q_atomic_decrement().

#### int q_atomic_decrement (volatile int *ptr)

Atomic integer decrement.

        --(*ptr);
        return *ptr ?  : 0;

Decrements the value in memory pointed to by ptr. This function returns zero if the new value of *ptr is zero; otherwise it returns a non-zero value.

Tip: Depending on the architecture, it may be easier to return the new value after incrementing *ptr:

        return --(*ptr);

Another option is to return the zero-flag that is set by some processors in control or status registers:

        --(*ptr);
        return !(ControlRegister & ZeroFlag);

See also q_atomic_increment().

#### int q_atomic_set_int (volatile int *ptr, int newval)

Atomic fetch-and-store for integers.

        tmp = *ptr;
        *ptr = newval;
        return tmp;

Sets the value in memory pointed to by ptr to newval and returns the previous value of *ptr.

See also q_atomic_set_ptr().

#### void *q_atomic_set_ptr (volatile void *ptr, void *newval)

Atomic fetch-and-store for pointers.

        tmp = *ptr;
        *ptr = newval;
        return tmp;

Sets the value in memory pointed to by ptr to newval and returns the previous value of *ptr.

See also q_atomic_set_int().

#### int q_atomic_fetch_and_add_int (volatile int *ptr, int value)

Atomic fetch-and-add for integers.

        tmp = *ptr;
        *ptr += value;
        return tmp;

Adds the value in memory pointed to by ptr with value and returns the previous value of *ptr;

There are 3 variants of the test-and-set integer function: Each variant implies a different memory semantic, i.e. the relation of memory operations before or after the test-and-set operation. Since modern hardware can reorder memory operations to improve performance, these functions are used to ensure the order of memory operations (often called a memory barrier).

Note: This variant of the test-and-set integer function implies that memory semantic is unspecified.

#### int q_atomic_fetch_and_add_acquire_int (volatile int *ptr, int value)

This function behaves essentially like the above function.

Note: This variant of the fetch-and-add integer function implies that the atomic fetch-and-add operation must be performed before memory operations after the fetch-and-add.

#### int q_atomic_fetch_and_add_release_int (volatile int *ptr, int value)

This function behaves essentially like the above function.

Note: This variant of the fetch-and-add integer function implies that all memory operations must be performed before the fetch-and-add.