Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/concurrency/Paper.tex

    r08b5a7e rf6f0d06f  
    5656\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
    5757\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
     58\newcommand{\R}[1]{\Textbf{#1}}
     59\newcommand{\B}[1]{{\Textbf[blue]{#1}}}
     60\newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
    5861\newcommand{\uC}{$\mu$\CC}
    59 \newcommand{\TODO}[1]{{\Textbf{#1}}}
     62\newcommand{\cit}{\textsuperscript{[Citation Needed]}\xspace}
     63\newcommand{\TODO}{{\Textbf{TODO}}}
    6064
    6165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    213217\lstMakeShortInline@%
    214218
     219\newcommand{\commenttd}[1]{{\color{red}{Thierry : #1}}}
     220
    215221\let\OLDthebibliography\thebibliography
    216222\renewcommand\thebibliography[1]{
     
    254260\section{Introduction}
    255261
    256 This paper provides a minimal concurrency \newterm{Application Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
     262This paper provides a minimal concurrency \newterm{Abstract Program Interface} (API) that is simple, efficient and can be used to build other concurrency features.
    257263While the simplest concurrency system is a thread and a lock, this low-level approach is hard to master.
    258264An easier approach for programmers is to support higher-level constructs as the basis of concurrency.
     
    304310`&`r3 = &y; `&&`r3 = &`&`r4;             // change r1, r2: cancel implicit dereferences (&*)**r3, (&(&*)*)*r3, &(&*)r4
    305311\end{cfa}
    306 A reference is a handle to an object, like a pointer, but is automatically dereferenced the specified number of levels.
     312A reference is a handle to an object, like a pointer, but is automatically dereferenced by the specified number of levels.
    307313Referencing (address-of @&@) a reference variable cancels one of the implicit dereferences, until there are no more implicit references, after which normal expression behaviour applies.
    308314
     
    474480
    475481The signature feature of \CFA is parametric-polymorphic routines~\cite{} with routines generalized using a @forall@ clause (giving the language its name), which allow separately compiled routines to support generic usage over multiple types.
    476 For example, the following sum routine works for any type that supports construction from 0 and addition:
     482For example, the following sum routine works for any type that supports construction from 0 and addition \commenttd{constructors have not been introduced yet.}:
    477483\begin{cfa}
    478484forall( otype T | { void `?{}`( T *, zero_t ); T `?+?`( T, T ); } ) // constraint type, 0 and +
     
    526532{
    527533        VLA  x,            y = { 20, 0x01 },     z = y; $\C{// z points to y}$
    528         //    x{};         y{ 20, 0x01 };          z{ z, y }; 
     534        //    x{};         y{ 20, 0x01 };          z{ z, y };
    529535        ^x{};                                                                   $\C{// deallocate x}$
    530536        x{};                                                                    $\C{// reallocate x}$
     
    563569The resulting execution system now follows a cooperative threading-model, called \newterm{non-preemptive scheduling}.
    564570
    565 Because the scheduler is special, it can either be a stackless or stackfull coroutine.
     571Because the scheduler is special, it can either be a stackless or stackfull coroutine. \commenttd{I dislike this sentence, it seems imply 1-step vs 2-step but also seems to say that some kind of coroutine is required, which is not the case.}
    566572For stackless, the scheduler performs scheduling on the stack of the current coroutine and switches directly to the next coroutine, so there is one context switch.
    567573For stackfull, the current coroutine switches to the scheduler, which performs scheduling, and it then switches to the next coroutine, so there are two context switches.
    568 A stackfull scheduler is often used for simplicity and security, even through there is a slightly higher runtime-cost.
     574A stackfull scheduler is often used for simplicity and security, even through there is a slightly higher runtime-cost. \commenttd{I'm not a fan of the fact that we don't quantify this but yet imply it is negligeable.}
    569575
    570576Regardless of the approach used, a subset of concurrency related challenges start to appear.
     
    583589As such, library support for threading is far from widespread.
    584590At the time of writing the paper, neither \protect\lstinline|gcc| nor \protect\lstinline|clang| support ``threads.h'' in their standard libraries.}.
    585 In modern programming languages, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
     591On modern architectures, a lack of threading is unacceptable~\cite{Sutter05, Sutter05b}, and therefore existing and new programming languages must have tools for writing efficient concurrent programs to take advantage of parallelism.
    586592As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers familiar with imperative languages.
    587593Furthermore, because C is a system-level language, programmers expect to choose precisely which features they need and which cost they are willing to pay.
     
    621627\newbox\myboxA
    622628\begin{lrbox}{\myboxA}
    623 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     629\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    624630`int f1, f2, state = 1;`   // single global variables
    625631int fib() {
     
    638644        }
    639645}
    640 \end{cfa}
     646\end{lstlisting}
    641647\end{lrbox}
    642648
    643649\newbox\myboxB
    644650\begin{lrbox}{\myboxB}
    645 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     651\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    646652#define FIB_INIT `{ 0, 1 }`
    647653typedef struct { int f2, f1; } Fib;
     
    660666        }
    661667}
    662 \end{cfa}
     668\end{lstlisting}
    663669\end{lrbox}
    664670
     
    673679\newbox\myboxA
    674680\begin{lrbox}{\myboxA}
    675 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     681\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    676682`coroutine` Fib { int fn; };
    677683void main( Fib & fib ) with( fib ) {
     
    693699        }
    694700}
    695 \end{cfa}
     701\end{lstlisting}
    696702\end{lrbox}
    697703\newbox\myboxB
    698704\begin{lrbox}{\myboxB}
    699 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     705\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    700706`coroutine` Fib { int ret; };
    701707void main( Fib & f ) with( fib ) {
     
    717723
    718724
    719 \end{cfa}
     725\end{lstlisting}
    720726\end{lrbox}
    721727\subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
     
    765771\newbox\myboxA
    766772\begin{lrbox}{\myboxA}
    767 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     773\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    768774`coroutine` Format {
    769775        char ch;   // used for communication
     
    771777};
    772778void main( Format & fmt ) with( fmt ) {
    773         for ( ;; ) {   
     779        for ( ;; ) {
    774780                for ( g = 0; g < 5; g += 1 ) {      // group
    775781                        for ( b = 0; b < 4; b += 1 ) { // block
     
    797803        }
    798804}
    799 \end{cfa}
     805\end{lstlisting}
    800806\end{lrbox}
    801807
    802808\newbox\myboxB
    803809\begin{lrbox}{\myboxB}
    804 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     810\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    805811struct Format {
    806812        char ch;
     
    834840        format( &fmt );
    835841}
    836 \end{cfa}
     842\end{lstlisting}
    837843\end{lrbox}
    838844\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     
    10401046};
    10411047\end{cfa}
    1042 &
    1043 {\Large $\Rightarrow$}
    1044 &
     1048& {\Large $\Rightarrow$} &
    10451049\begin{tabular}{@{}ccc@{}}
    10461050\begin{cfa}
     
    14431447\label{s:InternalScheduling}
    14441448
    1445 While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer, Figure~\ref{f:GenericBoundedBuffer}, may be full/empty so produce/consumer threads must block.
     1449While monitor mutual-exclusion provides safe access to shared data, the monitor data may indicate that a thread accessing it cannot proceed, \eg a bounded buffer, Figure~\ref{f:BoundedBuffer}, may be full/empty so produce/consumer threads must block.
    14461450Leaving the monitor and trying again (busy waiting) is impractical for high-level programming.
    14471451Monitors eliminate busy waiting by providing internal synchronization to schedule threads needing access to the shared data, where the synchronization is blocking (threads are parked) versus spinning.
    14481452The synchronization is generally achieved with internal~\cite{Hoare74} or external~\cite[\S~2.9.2]{uC++} scheduling, where \newterm{scheduling} is defined as indicating which thread acquires the critical section next.
    1449 \newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and on behalf of other threads attempting entry.
     1453\newterm{Internal scheduling} is characterized by each thread entering the monitor and making an individual decision about proceeding or blocking, while \newterm{external scheduling} is characterized by an entering thread making a decision about proceeding for itself and behalf of other threads attempting entry.
    14501454
    14511455Figure~\ref{f:BBInt} shows a \CFA bounded-buffer with internal scheduling, where producers/consumers enter the monitor, see the buffer is full/empty, and block on an appropriate condition lock, @full@/@empty@.
     
    14561460\begin{enumerate}
    14571461\item
    1458 The signalling thread returns immediately, and the signalled thread continues.
     1462The signalling thread leaves immediately, and the signalled thread continues.
    14591463\item
    1460 The signalling thread continues and the signalled thread is marked for urgent unblocking at the next scheduling point (exit/wait).
     1464The signalling thread continues and the signalled thread is marked for urgent unblocking at subsequent scheduling points (exit/wait).
    14611465\item
    1462 The signalling thread blocks but is marked for urgrent unblocking at the next scheduling point and the signalled thread continues.
     1466The signalling thread blocks but is marked for urgrent unblocking and the signalled thread continues.
    14631467\end{enumerate}
    14641468The first approach is too restrictive, as it precludes solving a reasonable class of problems (\eg dating service).
    14651469\CFA supports the next two semantics as both are useful.
    14661470Finally, while it is common to store a @condition@ as a field of the monitor, in \CFA, a @condition@ variable can be created/stored independently.
    1467 Furthermore, a condition variable is tied to a \emph{group} of monitors on first use (called \newterm{branding}), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors.
    14681471
    14691472\begin{figure}
     
    14711474\newbox\myboxA
    14721475\begin{lrbox}{\myboxA}
    1473 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1476\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    14741477forall( otype T ) { // distribute forall
    14751478        monitor Buffer {
     
    14951498        }
    14961499}
    1497 \end{cfa}
     1500\end{lstlisting}
    14981501\end{lrbox}
    14991502
    15001503\newbox\myboxB
    15011504\begin{lrbox}{\myboxB}
    1502 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     1505\begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
    15031506forall( otype T ) { // distribute forall
    15041507        monitor Buffer {
     
    15241527        }
    15251528}
    1526 \end{cfa}
     1529\end{lstlisting}
    15271530\end{lrbox}
    15281531
     
    15311534\subfloat[External Scheduling]{\label{f:BBExt}\usebox\myboxB}
    15321535\caption{Generic Bounded-Buffer}
    1533 \label{f:GenericBoundedBuffer}
     1536\label{f:BoundedBuffer}
    15341537\end{figure}
    15351538
     
    15371540External scheduling is controlled by the @waitfor@ statement, which atomically blocks the calling thread, releases the monitor lock, and restricts the routine calls that can next acquire mutual exclusion.
    15381541If the buffer is full, only calls to @remove@ can acquire the buffer, and if the buffer is empty, only calls to @insert@ can acquire the buffer.
    1539 Threads making calls to routines that are currently excluded block outside (externally) of the monitor on a calling queue, versus blocking on condition queues inside the monitor.
    1540 
    1541 Both internal and external scheduling extend to multiple monitors in a natural way.
    1542 \begin{cfa}
    1543 monitor M { `condition e`; ... };
    1544 void foo( M & mutex m1, M & mutex m2 ) {
    1545         ... wait( `e` ); ...                                    $\C{// wait( e, m1, m2 )}$
    1546         ... wait( `e, m1` ); ...
    1547         ... wait( `e, m2` ); ...
    1548 }
    1549 
    1550 void rtn$\(_1\)$( M & mutex m1, M & mutex m2 );
    1551 void rtn$\(_2\)$( M & mutex m1 );
    1552 void bar( M & mutex m1, M & mutex m2 ) {
    1553         ... waitfor( `rtn` ); ...                               $\C{// waitfor( rtn\(_1\), m1, m2 )}$
    1554         ... waitfor( `rtn, m1` ); ...                   $\C{// waitfor( rtn\(_2\), m1 )}$
    1555 }
    1556 \end{cfa}
    1557 For @wait( e )@, the default semantics is to atomically block the signaller and release all acquired mutex types in the parameter list, \ie @wait( e, m1, m2 )@.
    1558 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @wait( e, m1 )@.
    1559 Wait statically verifies the released monitors are the acquired mutex-parameters so unconditional release is safe.
    1560 Similarly, for @waitfor( rtn, ... )@, the default semantics is to atomically block the acceptor and release all acquired mutex types in the parameter list, \ie @waitfor( rtn, m1, m2 )@.
    1561 To override the implicit multi-monitor wait, specific mutex parameter(s) can be specified, \eg @waitfor( rtn, m1 )@.
    1562 Waitfor statically verifies the released monitors are the same as the acquired mutex-parameters of the given routine or routine pointer.
    1563 To statically verify the released monitors match with the accepted routine's mutex parameters, the routine (pointer) prototype must be accessible.
    1564 
    1565 Given the ability to release a subset of acquired monitors can result in a \newterm{nested monitor}~\cite{Lister77} deadlock.
    1566 \begin{cfa}
    1567 void foo( M & mutex m1, M & mutex m2 ) {
    1568         ... wait( `e, m1` ); ...                                $\C{// release m1, keeping m2 acquired )}$
    1569 void baz( M & mutex m1, M & mutex m2 ) {        $\C{// must acquire m1 and m2 )}$
    1570         ... signal( `e` ); ...
    1571 \end{cfa}
    1572 The @wait@ only releases @m1@ so the signalling thread cannot acquire both @m1@ and @m2@ to  enter @baz@ to get to the @signal@.
    1573 While deadlock issues can occur with multiple/nesting acquisition, this issue results from the fact that locks, and by extension monitors, are not perfectly composable.
    1574 
    1575 Finally, an important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
     1542Threads making calls to routines that are currently excluded wait outside (externally) of the monitor on a calling queue.
     1543
     1544An important aspect of monitor implementation is barging, \ie can calling threads barge ahead of signalled threads?
    15761545If barging is allowed, synchronization between a singller and signallee is difficult, often requiring multiple unblock/block cycles (looping around a wait rechecking if a condition is met).
    1577 \begin{quote}
    1578 However, we decree that a signal operation be followed immediately by resumption of a waiting program, without possibility of an intervening procedure call from yet a third program.
    1579 It is only in this way that a waiting program has an absolute guarantee that it can acquire the resource just released by the signalling program without any danger that a third program will interpose a monitor entry and seize the resource instead.~\cite[p.~550]{Hoare74}
    1580 \end{quote}
    1581 \CFA scheduling \emph{precludes} barging, which simplifies synchronization among threads in the monitor and increases correctness.
    1582 For example, there are no loops in either bounded buffer solution in Figure~\ref{f:GenericBoundedBuffer}.
     1546\CFA scheduling does \emph{not} have barging, which simplifies synchronization among threads in the monitor.
    15831547Supporting barging prevention as well as extending internal scheduling to multiple monitors is the main source of complexity in the design and implementation of \CFA concurrency.
    15841548
    1585 
    1586 \subsection{Barging Prevention}
    1587 
    1588 Figure~\ref{f:BargingPrevention} shows \CFA code where bulk acquire adds complexity to the internal-signalling semantics.
    1589 The complexity begins at the end of the inner @mutex@ statement, where the semantics of internal scheduling need to be extended for multiple monitors.
    1590 The problem is that bulk acquire is used in the inner @mutex@ statement where one of the monitors is already acquired.
    1591 When the signalling thread reaches the end of the inner @mutex@ statement, it should transfer ownership of @m1@ and @m2@ to the waiting thread to prevent barging into the outer @mutex@ statement by another thread.
    1592 However, both the signalling and signalled threads still need monitor @m1@.
     1549Indeed, like the bulk acquire semantics, internal scheduling extends to multiple monitors in a way that is natural to the user but requires additional complexity on the implementation side.
     1550
     1551First, here is a simple example of internal scheduling:
     1552
     1553\begin{cfa}
     1554monitor A {
     1555        condition e;
     1556}
     1557
     1558void foo(A& mutex a1, A& mutex a2) {
     1559        ...
     1560        // Wait for cooperation from bar()
     1561        wait(a1.e);
     1562        ...
     1563}
     1564
     1565void bar(A& mutex a1, A& mutex a2) {
     1566        // Provide cooperation for foo()
     1567        ...
     1568        // Unblock foo
     1569        signal(a1.e);
     1570}
     1571\end{cfa}
     1572
     1573% ======================================================================
     1574% ======================================================================
     1575\subsection{Internal Scheduling - Multi-Monitor}
     1576% ======================================================================
     1577% ======================================================================
     1578It is easy to understand the problem of multi-monitor scheduling using a series of pseudo-code examples.
     1579Note that for simplicity in the following snippets of pseudo-code, waiting and signalling is done using an implicit condition variable, like Java built-in monitors.
     1580Indeed, @wait@ statements always use the implicit condition variable as parameters and explicitly name the monitors (A and B) associated with the condition.
     1581Note that in \CFA, condition variables are tied to a \emph{group} of monitors on first use (called branding), which means that using internal scheduling with distinct sets of monitors requires one condition variable per set of monitors.
     1582The example below shows the simple case of having two threads (one for each column) and a single monitor A.
     1583
     1584\begin{multicols}{2}
     1585thread 1
     1586\begin{cfa}
     1587acquire A
     1588        wait A
     1589release A
     1590\end{cfa}
     1591
     1592\columnbreak
     1593
     1594thread 2
     1595\begin{cfa}
     1596acquire A
     1597        signal A
     1598release A
     1599\end{cfa}
     1600\end{multicols}
     1601One thread acquires before waiting (atomically blocking and releasing A) and the other acquires before signalling.
     1602It is important to note here that both @wait@ and @signal@ must be called with the proper monitor(s) already acquired.
     1603This semantic is a logical requirement for barging prevention.
     1604
     1605A direct extension of the previous example is a bulk acquire version:
     1606\begin{multicols}{2}
     1607\begin{cfa}
     1608acquire A & B
     1609        wait A & B
     1610release A & B
     1611\end{cfa}
     1612\columnbreak
     1613\begin{cfa}
     1614acquire A & B
     1615        signal A & B
     1616release A & B
     1617\end{cfa}
     1618\end{multicols}
     1619\noindent This version uses bulk acquire (denoted using the {\sf\&} symbol), but the presence of multiple monitors does not add a particularly new meaning.
     1620Synchronization happens between the two threads in exactly the same way and order.
     1621The only difference is that mutual exclusion covers a group of monitors.
     1622On the implementation side, handling multiple monitors does add a degree of complexity as the next few examples demonstrate.
     1623
     1624While deadlock issues can occur when nesting monitors, these issues are only a symptom of the fact that locks, and by extension monitors, are not perfectly composable.
     1625For monitors, a well-known deadlock problem is the Nested Monitor Problem~\cite{Lister77}, which occurs when a @wait@ is made by a thread that holds more than one monitor.
     1626For example, the following cfa-code runs into the nested-monitor problem:
     1627\begin{multicols}{2}
     1628\begin{cfa}
     1629acquire A
     1630        acquire B
     1631                wait B
     1632        release B
     1633release A
     1634\end{cfa}
     1635
     1636\columnbreak
     1637
     1638\begin{cfa}
     1639acquire A
     1640        acquire B
     1641                signal B
     1642        release B
     1643release A
     1644\end{cfa}
     1645\end{multicols}
     1646\noindent The @wait@ only releases monitor @B@ so the signalling thread cannot acquire monitor @A@ to get to the @signal@.
     1647Attempting release of all acquired monitors at the @wait@ introduces a different set of problems, such as releasing monitor @C@, which has nothing to do with the @signal@.
     1648
     1649However, for monitors as for locks, it is possible to write a program using nesting without encountering any problems if nesting is done correctly.
     1650For example, the next cfa-code snippet acquires monitors {\sf A} then {\sf B} before waiting, while only acquiring {\sf B} when signalling, effectively avoiding the Nested Monitor Problem~\cite{Lister77}.
     1651
     1652\begin{multicols}{2}
     1653\begin{cfa}
     1654acquire A
     1655        acquire B
     1656                wait B
     1657        release B
     1658release A
     1659\end{cfa}
     1660
     1661\columnbreak
     1662
     1663\begin{cfa}
     1664
     1665acquire B
     1666        signal B
     1667release B
     1668
     1669\end{cfa}
     1670\end{multicols}
     1671
     1672\noindent However, this simple refactoring may not be possible, forcing more complex restructuring.
     1673
     1674% ======================================================================
     1675% ======================================================================
     1676\subsection{Internal Scheduling - In Depth}
     1677% ======================================================================
     1678% ======================================================================
     1679
     1680A larger example is presented to show complex issues for bulk acquire and its implementation options are analyzed.
     1681Figure~\ref{f:int-bulk-cfa} shows an example where bulk acquire adds a significant layer of complexity to the internal signalling semantics, and listing \ref{f:int-bulk-cfa} shows the corresponding \CFA code to implement the cfa-code in listing \ref{f:int-bulk-cfa}.
     1682For the purpose of translating the given cfa-code into \CFA-code, any method of introducing a monitor is acceptable, \eg @mutex@ parameters, global variables, pointer parameters, or using locals with the @mutex@ statement.
    15931683
    15941684\begin{figure}
    1595 \newbox\myboxA
    1596 \begin{lrbox}{\myboxA}
    1597 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1598 monitor M m1, m2;
     1685\begin{multicols}{2}
     1686Waiting thread
     1687\begin{cfa}[numbers=left]
     1688acquire A
     1689        // Code Section 1
     1690        acquire A & B
     1691                // Code Section 2
     1692                wait A & B
     1693                // Code Section 3
     1694        release A & B
     1695        // Code Section 4
     1696release A
     1697\end{cfa}
     1698\columnbreak
     1699Signalling thread
     1700\begin{cfa}[numbers=left, firstnumber=10,escapechar=|]
     1701acquire A
     1702        // Code Section 5
     1703        acquire A & B
     1704                // Code Section 6
     1705                |\label{line:signal1}|signal A & B
     1706                // Code Section 7
     1707        |\label{line:releaseFirst}|release A & B
     1708        // Code Section 8
     1709|\label{line:lastRelease}|release A
     1710\end{cfa}
     1711\end{multicols}
     1712\begin{cfa}[caption={Internal scheduling with bulk acquire},label={f:int-bulk-cfa}]
     1713\end{cfa}
     1714\begin{center}
     1715\begin{cfa}[xleftmargin=.4\textwidth]
     1716monitor A a;
     1717monitor B b;
    15991718condition c;
    1600 mutex( m1 ) {
    1601         ...
    1602         mutex( m1, m2 ) {
    1603                 ... `wait( c )`; // block and release m1, m2
    1604                 // m1, m2 acquired
    1605         } // $\LstCommentStyle{\color{red}release m2}$
    1606         // m1 acquired
    1607 } // release m1
    1608 \end{cfa}
    1609 \end{lrbox}
    1610 
    1611 \newbox\myboxB
    1612 \begin{lrbox}{\myboxB}
    1613 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1614 
    1615 
    1616 mutex( m1 ) {
    1617         ...
    1618         mutex( m1, m2 ) {
    1619                 ... `signal( c )`; ...
    1620                 // m1, m2 acquired
    1621         } // $\LstCommentStyle{\color{red}release m2}$
    1622         // m1 acquired
    1623 } // release m1
    1624 \end{cfa}
    1625 \end{lrbox}
    1626 
    1627 \newbox\myboxC
    1628 \begin{lrbox}{\myboxC}
    1629 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1630 
    1631 
    1632 mutex( m1 ) {
    1633         ... `wait( c )`; ...
    1634         // m1 acquired
    1635 } // $\LstCommentStyle{\color{red}release m1}$
    1636 
    1637 
    1638 
    1639 
    1640 \end{cfa}
    1641 \end{lrbox}
    1642 
    1643 \begin{cquote}
    1644 \subfloat[Waiting Thread]{\label{f:WaitingThread}\usebox\myboxA}
    1645 \hspace{2\parindentlnth}
    1646 \subfloat[Signalling Thread]{\label{f:SignallingThread}\usebox\myboxB}
    1647 \hspace{2\parindentlnth}
    1648 \subfloat[Other Waiting Thread]{\label{f:SignallingThread}\usebox\myboxC}
    1649 \end{cquote}
    1650 \caption{Barging Prevention}
    1651 \label{f:BargingPrevention}
     1719\end{cfa}
     1720\end{center}
     1721\begin{multicols}{2}
     1722Waiting thread
     1723\begin{cfa}
     1724mutex(a) {
     1725        // Code Section 1
     1726        mutex(a, b) {
     1727                // Code Section 2
     1728                wait(c);
     1729                // Code Section 3
     1730        }
     1731        // Code Section 4
     1732}
     1733\end{cfa}
     1734\columnbreak
     1735Signalling thread
     1736\begin{cfa}
     1737mutex(a) {
     1738        // Code Section 5
     1739        mutex(a, b) {
     1740                // Code Section 6
     1741                signal(c);
     1742                // Code Section 7
     1743        }
     1744        // Code Section 8
     1745}
     1746\end{cfa}
     1747\end{multicols}
     1748\begin{cfa}[caption={Equivalent \CFA code for listing \ref{f:int-bulk-cfa}},label={f:int-bulk-cfa}]
     1749\end{cfa}
     1750\begin{multicols}{2}
     1751Waiter
     1752\begin{cfa}[numbers=left]
     1753acquire A
     1754        acquire A & B
     1755                wait A & B
     1756        release A & B
     1757release A
     1758\end{cfa}
     1759
     1760\columnbreak
     1761
     1762Signaller
     1763\begin{cfa}[numbers=left, firstnumber=6,escapechar=|]
     1764acquire A
     1765        acquire A & B
     1766                signal A & B
     1767        release A & B
     1768        |\label{line:secret}|// Secretly keep B here
     1769release A
     1770// Wakeup waiter and transfer A & B
     1771\end{cfa}
     1772\end{multicols}
     1773\begin{cfa}[caption={Figure~\ref{f:int-bulk-cfa}, with delayed signalling comments},label={f:int-secret}]
     1774\end{cfa}
    16521775\end{figure}
    16531776
     1777The complexity begins at code sections 4 and 8 in listing \ref{f:int-bulk-cfa}, which are where the existing semantics of internal scheduling needs to be extended for multiple monitors.
     1778The root of the problem is that bulk acquire is used in a context where one of the monitors is already acquired, which is why it is important to define the behaviour of the previous cfa-code.
     1779When the signaller thread reaches the location where it should ``release @A & B@'' (listing \ref{f:int-bulk-cfa} line \ref{line:releaseFirst}), it must actually transfer ownership of monitor @B@ to the waiting thread.
     1780This ownership transfer is required in order to prevent barging into @B@ by another thread, since both the signalling and signalled threads still need monitor @A@.
     1781There are three options:
     1782
     1783\subsubsection{Delaying Signals}
    16541784The obvious solution to the problem of multi-monitor scheduling is to keep ownership of all locks until the last lock is ready to be transferred.
    16551785It can be argued that that moment is when the last lock is no longer needed, because this semantics fits most closely to the behaviour of single-monitor scheduling.
     
    16641794Depending on the order of signals (listing \ref{f:dependency} line \ref{line:signal-ab} and \ref{line:signal-a}) two cases can happen:
    16651795
    1666 \begin{comment}
    16671796\paragraph{Case 1: thread $\alpha$ goes first.} In this case, the problem is that monitor @A@ needs to be passed to thread $\beta$ when thread $\alpha$ is done with it.
    16681797\paragraph{Case 2: thread $\beta$ goes first.} In this case, the problem is that monitor @B@ needs to be retained and passed to thread $\alpha$ along with monitor @A@, which can be done directly or possibly using thread $\beta$ as an intermediate.
     
    16741803In both cases, the threads need to be able to distinguish, on a per monitor basis, which ones need to be released and which ones need to be transferred, which means knowing when to release a group becomes complex and inefficient (see next section) and therefore effectively precludes this approach.
    16751804
    1676 
    16771805\subsubsection{Dependency graphs}
     1806
    16781807
    16791808\begin{figure}
     
    17541883
    17551884\subsubsection{Partial Signalling} \label{partial-sig}
    1756 \end{comment}
    1757 
    17581885Finally, the solution that is chosen for \CFA is to use partial signalling.
    17591886Again using listing \ref{f:int-bulk-cfa}, the partial signalling solution transfers ownership of monitor @B@ at lines \ref{line:signal1} to the waiter but does not wake the waiting thread since it is still using monitor @A@.
     
    17701897\end{itemize}
    17711898
    1772 
     1899% ======================================================================
     1900% ======================================================================
    17731901\subsection{Signalling: Now or Later}
    1774 
    1775 \begin{figure}
    1776 \centering
    1777 \newbox\myboxA
    1778 \begin{lrbox}{\myboxA}
    1779 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1780 enum { CCodes = 20 };
    1781 monitor DS {
    1782         int GirlPhNo, BoyPhNo;
    1783         condition Girls[CCodes], Boys[CCodes];
    1784         condition exchange;
     1902% ======================================================================
     1903% ======================================================================
     1904\begin{table}
     1905\begin{tabular}{|c|c|}
     1906@signal@ & @signal_block@ \\
     1907\hline
     1908\begin{cfa}[tabsize=3]
     1909monitor DatingService {
     1910        // compatibility codes
     1911        enum{ CCodes = 20 };
     1912
     1913        int girlPhoneNo
     1914        int boyPhoneNo;
    17851915};
    1786 int girl( DS & mutex ds, int phNo, int ccode ) {
    1787         if ( is_empty( Boys[ccode] ) ) {
    1788                 wait( Girls[ccode] );
    1789                 GirlPhNo = phNo;
    1790                 exchange.signal();
     1916
     1917condition girls[CCodes];
     1918condition boys [CCodes];
     1919condition exchange;
     1920
     1921int girl(int phoneNo, int cfa) {
     1922        // no compatible boy ?
     1923        if(empty(boys[cfa])) {
     1924                wait(girls[cfa]);               // wait for boy
     1925                girlPhoneNo = phoneNo;          // make phone number available
     1926                signal(exchange);               // wake boy from chair
    17911927        } else {
    1792                 GirlPhNo = phNo;
    1793                 signal( Boys[ccode] );
    1794                 exchange.wait();
    1795         } // if
    1796         return BoyPhNo;
    1797 }
    1798 int boy( DS & mutex ds, int phNo, int ccode ) {
    1799         // as above with boy/girl interchanged
    1800 }
    1801 \end{cfa}
    1802 \end{lrbox}
    1803 
    1804 \newbox\myboxB
    1805 \begin{lrbox}{\myboxB}
    1806 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    1807 
    1808 monitor DS {
    1809         int GirlPhNo, BoyPhNo;
    1810         condition Girls[CCodes], Boys[CCodes];
    1811 
     1928                girlPhoneNo = phoneNo;          // make phone number available
     1929                signal(boys[cfa]);              // wake boy
     1930                wait(exchange);         // sit in chair
     1931        }
     1932        return boyPhoneNo;
     1933}
     1934int boy(int phoneNo, int cfa) {
     1935        // same as above
     1936        // with boy/girl interchanged
     1937}
     1938\end{cfa}&\begin{cfa}[tabsize=3]
     1939monitor DatingService {
     1940
     1941        enum{ CCodes = 20 };    // compatibility codes
     1942
     1943        int girlPhoneNo;
     1944        int boyPhoneNo;
    18121945};
    1813 int girl( DS & mutex ds, int phNo, int ccode ) {
    1814         if ( is_empty( Boys[ccode] ) ) { // no compatible
    1815                 wait( Girls[ccode] ); // wait for boy
    1816                 GirlPhNo = phNo; // make phone number available
    1817 
     1946
     1947condition girls[CCodes];
     1948condition boys [CCodes];
     1949// exchange is not needed
     1950
     1951int girl(int phoneNo, int cfa) {
     1952        // no compatible boy ?
     1953        if(empty(boys[cfa])) {
     1954                wait(girls[cfa]);               // wait for boy
     1955                girlPhoneNo = phoneNo;          // make phone number available
     1956                signal(exchange);               // wake boy from chair
    18181957        } else {
    1819                 GirlPhNo = phNo; // make phone number available
    1820                 signal_block( Boys[ccode] ); // restart boy
    1821 
    1822         } // if
    1823         return BoyPhNo;
    1824 }
    1825 int boy( DS & mutex ds, int phNo, int ccode ) {
    1826         // as above with boy/girl interchanged
    1827 }
    1828 \end{cfa}
    1829 \end{lrbox}
    1830 
    1831 \subfloat[\lstinline@signal@]{\label{f:DatingSignal}\usebox\myboxA}
    1832 \qquad
    1833 \subfloat[\lstinline@signal_block@]{\label{f:DatingSignalBlock}\usebox\myboxB}
    1834 \caption{Dating service. }
    1835 \label{f:Dating service}
    1836 \end{figure}
    1837 
     1958                girlPhoneNo = phoneNo;          // make phone number available
     1959                signal_block(boys[cfa]);                // wake boy
     1960
     1961                // second handshake unnecessary
     1962
     1963        }
     1964        return boyPhoneNo;
     1965}
     1966
     1967int boy(int phoneNo, int cfa) {
     1968        // same as above
     1969        // with boy/girl interchanged
     1970}
     1971\end{cfa}
     1972\end{tabular}
     1973\caption{Dating service example using \protect\lstinline|signal| and \protect\lstinline|signal_block|. }
     1974\label{tbl:datingservice}
     1975\end{table}
    18381976An important note is that, until now, signalling a monitor was a delayed operation.
    18391977The ownership of the monitor is transferred only when the monitor would have otherwise been released, not at the point of the @signal@ statement.
     
    18521990% ======================================================================
    18531991An alternative to internal scheduling is external scheduling (see Table~\ref{tbl:sched}).
    1854 
    1855 \begin{comment}
    18561992\begin{table}
    18571993\begin{tabular}{|c|c|c|}
     
    19172053\label{tbl:sched}
    19182054\end{table}
    1919 \end{comment}
    1920 
    19212055This method is more constrained and explicit, which helps users reduce the non-deterministic nature of concurrency.
    19222056Indeed, as the following examples demonstrate, external scheduling allows users to wait for events from other threads without the concern of unrelated events occurring.
Note: See TracChangeset for help on using the changeset viewer.