Skip to content

Commit adcb95c

Browse files
committed
Proofread
1 parent f965f1f commit adcb95c

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

concurrency-primer.tex

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ \subsection{Compare and swap}
494494

495495
\begin{samepage}
496496
\noindent The \texttt{\_strong} suffix may leave you wondering if there is a corresponding ``weak'' \textsc{CAS}.
497-
Indeed, there is. However, we will delve into that topic later in \secref{spurious-ll/sc-failures}.
497+
Indeed, there is. However, we will delve into that topic later in \secref{spurious-llsc-failures}.
498498
\end{samepage}
499499

500500
Let's say we have some long-running task that we might want to cancel.
@@ -657,7 +657,7 @@ \section{Implementing atomic read-modify-write operations with LL/SC instruction
657657
} architectures, \textsc{Arm} does not have dedicated \textsc{RMW} instructions.
658658
Given that the processor may switch contexts to another thread at any moment,
659659
constructing \textsc{RMW} operations from standard loads and stores is not feasible.
660-
Special instructions are required instead: \introduce{load-link} and \introduce{store-conditional} (\textsc{ll/sc}).
660+
Special instructions are required instead: \introduce{load-link} and \introduce{store-conditional} (\textsc{LL/SC}).
661661
These instructions are complementary:
662662
load-link performs a read operation from an address, similar to any load,
663663
but it also signals the processor to watch that address.
@@ -684,26 +684,24 @@ \section{Implementing atomic read-modify-write operations with LL/SC instruction
684684
bx lr
685685
\end{lstlisting}
686686
\end{colfigure}
687-
We \textsc{ll} the current value, add one, and immediately try to store it back with a \textsc{sc}.
688-
If that fails, another thread may have written to \texttt{foo} since our \textsc{ll}, so we try again.
687+
We \textsc{LL} the current value, add one, and immediately try to store it back with a \textsc{SC}.
688+
If that fails, another thread may have written to \texttt{foo} since our \textsc{LL}, so we try again.
689689
In this way, at least one thread is always making forward progress in atomically modifying \texttt{foo},
690690
even if several are attempting to do so at once.\punckern\footnote{%
691691
\ldots though generally,
692692
we want to avoid cases where multiple threads are vying for the same variable for any significant amount of time.}
693693

694694
\subsection{Spurious LL/SC failures}
695-
\label{spurious-ll/sc-failures}
696-
697-
As you might imagine, it would take too much \textsc{CPU} hardware to track load-linked addresses for every single byte on the machine.
698-
To reduce this cost, many processors monitor them at some coarser granularity,
699-
such as the cache line.
700-
This means that a \textsc{sc} can fail if it is preceded by a write to \emph{any} address in the monitored block,
701-
not just the specific one that was load-linked.
702-
703-
This is especially troublesome for compare and swap,
704-
and is the raison d'être for \monobox{compare\_exchange\_weak}.
705-
To see why, consider a function that atomically multiplies a value,
706-
even though there's no atomic instruction to read-multiply-write in any common architecture.
695+
\label{spurious-llsc-failures}
696+
697+
It is impractical for \textsc{CPU} hardware to track load-linked addresses for each byte within a system due to the immense resource requirements.
698+
To mitigate this, many processors monitor these operations at a broader scale, like the cache line level.
699+
Consequently, a \textsc{SC} operation may fail if any part of the monitored block is written to,
700+
not just the specific address that was load-linked.
701+
702+
This limitation poses a particular challenge for operations like compare and swap,
703+
highlighting the essential purpose of \monobox{compare\_exchange\_weak}.
704+
Consider, for example, the task of atomically multiplying a value without an architecture-specific atomic read-multiply-write instruction.
707705
\begin{colfigure}
708706
\begin{minted}[fontsize=\codesize]{cpp}
709707
void atomicMultiply(int by)
@@ -727,13 +725,13 @@ \subsection{Spurious LL/SC failures}
727725
\end{enumerate}
728726
If we use \monobox{compare\_exchange\_strong} for this family of algorithms,
729727
the compiler must emit nested loops:
730-
an inner one to protect us from spurious \textsc{sc} failures,
728+
an inner one to protect us from spurious \textsc{SC} failures,
731729
and an outer one which repeatedly performs our operation until no other thread has interrupted us.
732730
But unlike the \monobox{\_strong} version,
733-
a weak \textsc{CAS} is allowed to fail spuriously, just like the \textsc{ll/sc} mechanism that implements it.
731+
a weak \textsc{CAS} is allowed to fail spuriously, just like the \textsc{LL/SC} mechanism that implements it.
734732
So, with \monobox{compare\_exchange\_weak},
735733
the compiler is free to generate a single loop,
736-
since we do not care about the difference between retries from spurious \textsc{sc} failures and retries caused by another thread modifying our variable.
734+
since we do not care about the difference between retries from spurious \textsc{SC} failures and retries caused by another thread modifying our variable.
737735

738736
\section{Do we always need sequentially consistent operations?}
739737
\label{lock-example}

0 commit comments

Comments
 (0)