Compare and swap
Finally, we have compare-and-swap (CAS), sometimes called compare-and-exchange. It allows us to conditionally exchange a value if its previous value matches some expected one. In C and C++, CAS resembles the following, if it were executed atomically:
template <typename T>
bool atomic<T>::compare_exchange_strong(
T& expected, T desired)
{
if (*this == expected) {
*this = desired;
return true;
}
expected = *this;
return false;
}
The compare_exchange_strong
suffix may leave you wondering if there is a corresponding “weak” CAS.
Indeed, there is. However, we will delve into that topic later in chapter Spurious LL/SC failures.
Let’s say we have some long-running task that we might want to cancel.
We’ll give it three states: idle, running, and cancelled, and write a loop that exits when it is cancelled.
enum class TaskState : int8_t {
Idle, Running, Cancelled
};
std::atomic<TaskState> ts;
void taskLoop()
{
ts = TaskState::Running;
while (ts == TaskState::Running) {
// Do good work.
}
}
If we want to cancel the task if it is running, but do nothing if it is idle, we could CAS:
bool cancel()
{
auto expected = TaskState::Running;
return ts.compare_exchange_strong(expected, TaskState::Cancelled);
}