<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% flag to use fancy fonts / graphics
\newif\ifjnf\jnftrue

\documentclass[11pt]{article}

\usepackage{tikz}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{amsthm}
\usepackage[margin=1in]{geometry}

\usepackage{csnotes}

\begin{document}

\header{1 November 2011}{Norris Xu}

\section{Atomic Bank Transfer with Locks}
We want to atomically transfer funds between accounts. We can synchronize the
withdraw method, but this is not enough: we can still be interrupted between
\texttt{from.withdraw(amount)} and \texttt{to.deposit(amount)}; at this time,
\texttt{amount} is in neither account.

One way to solve this is by adding explicit locks:
\begin{verbatim}
    from.lock();
    to.lock();
    ...
    from.unlock();
    to.unlock();
\end{verbatim}
However, this is prone to deadlock. We can avoid this by imposing an ordering on
the locks when getting them, and this does work, but it is very complicated.

\vspace{0.5cm}
Common problems with locks:
\begin{itemize}
    \item \textbf{Taking too many locks:} breaks atomicity
    \item \textbf{Taking too few locks:} inhibits concurrency
    \item \textbf{Taking the wrong locks:} the lock-data connection is implicit
    \item \textbf{Taking locks in the wrong order:} hard to avoid deadlocks
    \item \textbf{Error recovery:} hard with exceptions
    \item \textbf{Lost wake-ups:} hard with non-standard control
\end{itemize}
Locks are anti-modular!

\newpage
\section{Review: Haskell}
\subsection{Side Effects in Haskell}
\begin{verbatim}
    newRef   :: a -&gt; IO (Ref a)
    readRef  :: Ref a -&gt; IO a
    writeRef :: Ref a -&gt; a -&gt; IO ()

    do { r &lt;- newRef O
       ; incR r
       ; s &lt;- readRef r
       ; print s }

    incR :: Ref Int -&gt; IO ()
    incR r = do { v &lt;- readRef r
                ; writeRef r (v + 1) }
\end{verbatim}
\texttt{IO} is a monad, and \texttt{Ref} is a mutable object. \texttt{Ref}'s
side effects are embedded in \texttt{IO} (see monad notes).

\subsection{Concurrency in Haskell}
\begin{verbatim}
    fork::IO a -&gt; IO ThreadId

    do { r &lt;- newRef O
*      ; fork (incR r)
*      ; incR r
       ; s &lt;- readRef r
       ; print s }

    incR :: Ref Int -&gt; IO ()
    incR r = do { v &lt;- readRef r
                ; writeRef r (v + 1) }
\end{verbatim}
There is a data race between the two lines marked with `*'.

\section{Atomic Bank Transfer with Haskell STM}
\texttt{atomically :: STM a -&gt; IO a} guarantees:
\begin{itemize}
    \item \textbf{Atomicity:} effects of the embedded action become visible all
        at once
    \item \textbf{Isolation:} completely unaffected by other threads; as if the
        embedded action gets a snapshot of the world
\end{itemize}

We also introduce transaction variables, which are essentially \texttt{Ref}s in
the \texttt{STM} monad instead of in \texttt{IO}:
\begin{verbatim}
    newTVar   :: a -&gt; STM (TVar a)
    readTVar  :: TVar a -&gt; STM a
    writeTVar :: TVar a -&gt; a -&gt; STM ()
\end{verbatim}
\newpage
We could then implement \texttt{transfer} in this way:
\begin{verbatim}
    type Account = TVar Int

    withdraw :: Account -&gt; Int -&gt; STM ()
    withdraw acc amount
      = do { bal &lt;- readTVar acc
           ; writeTVar acc (bal - amount) }

    deposit :: Account -&gt; Int -&gt; STM ()
    deposit acc amount = withdraw acc (- amount)

    transfer :: Account -&gt; Account -&gt; Int -&gt; STM ()
    -- Transfer 'amount' from account 'from' to account 'to'
    transfer from to amount
      = atomically (do { deposit  to   amount
                       ; withdraw from amount })
\end{verbatim}

\section{More about Haskell STM}
Transactions might be aborted or re-tried, so they must not have side-effects
(outside of \texttt{STM} monad/inside of \texttt{IO} monad), such as shown
below:
\begin{verbatim}
    atomic $ if x &gt; y then launchMissiles
\end{verbatim}
However, the type system prevents this kind of error:
\begin{verbatim}
    bad :: Account -&gt; IO ()
    bad acc = do { hPutStr stdout "Withdrawing..."
                 ; withdraw acc 10 }
\end{verbatim}
The \texttt{hPutStr} conflicts with the \texttt{withdraw} since they have
effects in different monads \texttt{IO} and \texttt{STM}, respectively; it is
therefore a type error to compose them. We can fix this by converting the
\texttt{STM} monad to an \texttt{IO} monad:
\begin{verbatim}
    good :: Account -&gt; IO ()
    good acc = do { hPutStr stdout "Withdrawing..."
                 ; atomically (withdraw acc 10) }
\end{verbatim}
However, it is important to note that \texttt{hPutStr} and \texttt{withdraw} are
not executed atomically here: we can get interrupted after printing but before
actually withdrawing.

How do we debug when we can't print everywhere? We can use
\texttt{UnsafePerformIO :: IO a -&gt; a} to unsafely pass typechecking to print or
launch missiles.

\newpage
We use \texttt{retry :: STM a} to abort and retry the current STM. This is
useful if we e.g. need to wait for an event to occur before we can proceed with
the transaction. We can then add a check on the current balance to
\texttt{withdraw} to prevent overdraft:
\begin{verbatim}
    limitedWithdraw :: Account -&gt; Int -&gt; STM ()
    limitedWithdraw acc amount
      = do { bal &lt;- readTVar acc
           ; if amount &gt; 0 &amp;&amp; amount &gt; bal
             then retry
             else writeTVar acc (bal - amount) }
\end{verbatim}
We introduce a new function \texttt{check} to generalize this:
\begin{verbatim}
    check :: Bool -&gt; STM ()
    check True  = return ()
    check False = retry
\end{verbatim}
\texttt{limitedWithdrawn} can be rewritten to use \texttt{check}:
\begin{verbatim}
    limitedWithdraw :: Account -&gt; Int -&gt; STM ()
    limitedWithdraw acc amount
      = do { bal &lt;- readTVar acc
           ; check (amount &lt;= 0 || amount &lt;= bal)
           ; writeTVar acc (bal - amount) }
\end{verbatim}
We introduce a new function \texttt{orElse :: STM a -&gt; STM a -&gt; STM a}, which
tries two choices biased towards the first. Here is an example,
\texttt{limitedWithdraw2}, which attempts to withdraw from one of two accounts:
\begin{verbatim}
    limitedWithdraw2 :: Account -&gt; Account -&gt; Int -&gt; STM ()
    -- (limitedWithdraw2 acc1 acc2 amt) withdraws amt from acc1,
    -- if acc1 has enough money, otherwise from acc2.
    -- If neither has enough, it retries.
    limitedWithdraw2 acc1 acc2 amt
      = orElse (limitedWithdraw acc1 amt) (limitedWithdraw acc2 amt)
\end{verbatim}

\vspace{0.5cm}
The \texttt{STM} monad has built-in support for exceptions:
\begin{verbatim}
    throw :: Exception -&gt; STM a
    catch :: STM a -&gt; (Exception -&gt; STM a) -&gt; STM a
\end{verbatim}
We can also check invariants using \texttt{always :: STM Bool -&gt; STM ()}. Here
is an example that prevents an account's balance from ever becoming negative:
\begin{verbatim}
    checkBal   :: TVar Int -&gt; STM Bool
    checkBal v = do cts &lt;- readTVar v
                    return (v &gt;= 0)

    newAccount :: STM (TVar Int)
    newAccount = do v &lt;- newTVar 0
                 always $ checkBal v
                 return v
\end{verbatim}
Any transactions that modify the account will always check the invariant. The
invariant can be violated \textit{during} a transaction, so long as it is
satisfied before and after.

\section{Optimistic Execution}
Here is one model of optimistic execution:
\begin{enumerate}
    \item No locks needed to execute an action
    \item Record \texttt{writeTVar} in log
    \item Record \texttt{readTVar} if not written by this action
    \item On completion of action, validate the log; i.e., check that each
        \texttt{readTVar} matches the actual value
    \item If validation succeeds, commit
    \item Otherwise, abort and retry
\end{enumerate}
More sophisticated implementations are also possible.

\vspace{0.5cm}
How well does this perform? As the number of threads increases, STM's time spent
per operation grows much more slowly using optimistic execution than using
coarse- or fine-grained locking.

However, there is a problem with optimistic execution: what if a transaction
fails over and over? To address this, we should perform early checks for
conflicts so that we can abort early.

\section{Java STM}
An ordinary \texttt{Object} is wrapped within a \texttt{TMObject} to become a
transactional object; thus, \texttt{TMObject} is the Java analogue of
\texttt{TVar}. \texttt{TMObject}'s methods require the wrapped \texttt{Object}
to be cloneable.

\vspace{0.5cm}
\texttt{TMObject}s have explicit read/write modes. It is possible to explicitly
release read access to a \texttt{TMObject} using its \texttt{release()} method,
but this is unsafe: other transactions are now able to modify that
\texttt{TMObject}, yet the current transaction has not yet committed. It is up
to the programmer to ensure safety in this situation. This unsafeness is
reminiscent of the lock idiom. Can we check safeness of release during log
validation?

\vspace{0.5cm}
Unlike \texttt{TVar}s, any access to a \texttt{TMObject} can throw a
\texttt{Denied} exception. This allows us to abort earlier, but seems to be
exposing low-level mechanisms.

\vspace{0.5cm}
Each \texttt{TMObject} contains \texttt{Locator} objects; these represent its
state. Each \texttt{Locator} object contains the old and new object values, as
well as the status of the current transaction. Commits and aborts are performed
by atomically swapping locators using pointer swapping.

\vspace{0.5cm}
Java STM supports plugging in any implementation of a ``contention manager'',
which is in charge of transaction aborting strategy; i.e., whether to keep
waiting or give up and abort a transaction.

\end{document}
</pre></body></html>