<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2075: Progress guarantees, lock-free property, and scheduling assumptions</title>
<meta property="og:title" content="Issue 2075: Progress guarantees, lock-free property, and scheduling assumptions">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2075.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#Resolved">Resolved</a> status.</em></p>
<h3 id="2075"><a href="lwg-defects.html#2075">2075</a>. Progress guarantees, lock-free property, and scheduling assumptions</h3>
<p><b>Section:</b> 6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>, 32.5.5 <a href="https://wg21.link/atomics.lockfree">[atomics.lockfree]</a>, 99 [atomics.types.operations.req] <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Torvald Riegel <b>Opened:</b> 2011-08-18 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#intro.multithread">issues</a> in [intro.multithread].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>

<p>
According to 6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a> p2: 
</p>
<blockquote><p>
"Implementations should ensure that all unblocked threads eventually make progress."
</p></blockquote>
<ul>
<li>If taken literally, this cannot be achieved with lock-free atomics in
 general because they only guarantee that some thread makes progress
 (i.e., minimal progress, whereas 6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a> p2 seems to 
 require maximal progress).
</li>
<li>What does it mean precisely to "make progress"? Does "unblocked
 threads" exclude live-locked threads (if so, lock-free atomics would
 be sufficient I suppose)?
</li>
<li><p>Which assumptions can an implementation make about the thread
 scheduling? This is relevant for how implementations implement
 compare-exchange with load-linked &#47; store conditional (LL-SC), and
 atomic read-modifiy-write operations with load...compare-exchange-weak
 loops.
</p>
<ul>
<li>Do threads run long enough without being descheduled (e.g.,
   OS timeslices are long enough, interrupt frequency is not too
   high, etc.)?
</li>
<li>Or is this implementation-defined, and the sentence is just about
   stating that the progress guarantees will not hold on, for example,
   systems with unfair scheduling or thread priorities?
</li>
</ul>
</li>
</ul>

<p>
32.5.5 <a href="https://wg21.link/atomics.lockfree">[atomics.lockfree]</a> p2 declares the lock-free property for a
particular object. However, "lock-free" is never defined, and in discussions 
that I had with committee members it seemed as if the standard's lock-free would be
different from what lock-free means in other communities (eg, research,
text books on concurrent programming, etc.).
</p>
<ul>
<li>Originally, lock-freedom for an object requires minimal progress (ie,
 some thread makes progress, but other threads might never do) without
 any assumptions about the scheduling (threads could be stopped
 executing (so it is "nonblocking"), and threads are not guaranteed to
 execute in isolation, even for very small intervals of cycles).
</li>
<li>In contrast, obstruction-freedom, another nonblocking progress
 condition, guarantees progress for all threads that eventually get
 executed long enough in isolation (ie, without interference by other
 threads).
</li>
<li>Simple load...compare-exchange-weak loops (or LL-SC loops) to
 implement atomic read-modify-write operations can be just
 obstruction-free but not lock-free because they can livelock
 (depending on the hardware's LL-SC implementation, though). However,
 they effectively guarantee the same as lock-free iff threads will
 eventually run in isolation for long enough (that can be an assumption
 about the OS scheduler), or if the implementation adds this (e.g.,
 probabilistically by employing randomized exponential back-off when
 contention is detected, in all operations that can create contention).
</li>
<li>Does the particular object has to be lock-free, or is it only required
 that threads make progress irrespective on which object? Again
 considering compare-exchange-weak or LL-SC here, what happens if the
 compare-exchange object shares a cacheline with an integer counter
 object that is constantly updated by other threads? The
 compare-exchange-weak can always fail, so the object would not be
 lock-free. However, if we consider progress to be overall progress for
 threads, it would be lock-free because other threads succeed updating
 the integer counter. I would have assumed the lock-free property is
 strictly about the atomic object, but in discussions with committee
 members it seemed as if progress for any object could be the intended
 guarantee.
</li>
</ul>

<p>
Following 99 [atomics.types.operations.req] p7 <code>is_lock_free()</code> 
returns "true if the object is lock-free". What is returned if the object is only 
sometimes lock-free?
</p>

<p>
Basically, I would like to see clarifications for the progress
guarantees so that users know what they can expect from implementations
(and what they cannot expect!), and to give implementors a clearer
understanding of which user expectations they have to implement.
</p>
<ol>
<li><p>Elaborate on the intentions of the progress guarantee in 
6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a> p2. As I don't know about your intentions, 
it's hard to suggest a resolution.
</p>
<ul>
<li>Is it for straightforward, non-synchronizing code only?</li>
<li>Is it for blocking code only? (Is "unblocked" more than blocked on
 external I/O or on deadlocks?)
</li>
<li>What does it mean to "make progress"?</li>
<li>Is this meant to only waive any progress guarantees if there are
 thread priorities?
</li>
<li>Can an implementation make any assumptions about thread scheduling?
</li>
</ul>
</li>
<li><p>Define the lock-free property. The definition should probably include
the following points:
</p>
<ul>
<li>Is it just nonblocking, or what is the distinction to just being nonblocking?</li>
<li>Does it make any assumptions about the scheduler?</li>
<li>What are the progress guarantees, minimal or maximal (some or all threads finish eventually).</li>
<li>Is progress guaranteed for all operations on the particular object, or
 do operations on other objects also count as "making progress"?
</li>
</ul>
</li>
<li>Add a note explaining that compare-exchange-weak is not necessarily
lock-free (but is nonblocking)? Or is it indeed intended to be lock-free
(only allowed to fail spuriously but guaranteed to not fail eventually)?
Implementing the latter might be a challenge on LL-SC machines or lead
to space overheads I suppose, see the cacheline sharing example above.
</li>
</ol>

<p><i>[2011-12-01: Hans comments]</i></p>


<p>
6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a> p2 was an intentional compromise, and it was understood at the 
time that it was not a precise statement.  The wording was introduced by 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3209.htm">N3209</a>, which 
discusses some of the issues. There were additional reflector discussions.
<p/>
This is somewhat separable from the question of what lock-free means, which is probably a more 
promising question to focus on.
</p>

<p><i>[2012, Kona]</i></p>

<p>
General direction: lock-free means obstruction-free. Leave the current "should" recommendation 
for progress. It would take a lot of effort to try to do better. 
</p>


<p><i>[2012, Portland: move to Open]</i></p>

<p>
The current wording of 6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a> p2 doesn't really say very much.
As far as we can tell the term <i>lock-free</i> is nowhere defined in the standard.
</p>
<p>
James: we would prefer a different way to phrase it.
</p>
<p>
Hans: the research literature includes the term <i>abstraction-free</i> which might be a better fit.
</p>
<p>
Detlef: does Posix define a meaning for blocking (or locking) that we could use?
</p>
<p>
Hans: things like compare-exchange-strong can wait indefinitely.
</p>
<p>
Niklas: what about spin-locks -- still making no progress.
</p>
<p>
Hans: suspect we can only give guidance, at best. The lock-free meaning from the theoretical commmunity (forard progress will be made) is probably too strong here.
</p>
<p>
Atrur: what about livelocks?
</p>
<p>
Hans: each atomic <i>modification</i> completes, even if the whole thing is blocked.
</p>
<p>
Moved to open.
</p>

<p><i>[2013-11-06: Jason Hearne-McGuiness comments]</i></p>


<p>
Related to this issue, the wording in 32.5.5 <a href="https://wg21.link/atomics.lockfree">[atomics.lockfree]</a> p2,
</p>
<blockquote><p>
In any given program execution, the result of the lock-free query
shall be consistent for all pointers of the same type.
</p></blockquote>
<p>
should be made clearer, because the object-specific (non-static) nature of the <code>is_lock_free()</code> functions 
from 32.5.8 <a href="https://wg21.link/atomics.types.generic">[atomics.types.generic]</a> and 32.5.8.2 <a href="https://wg21.link/atomics.types.operations">[atomics.types.operations]</a> imply that for different 
instances of pointers of the same type the returned value could be different.
</p>



<p id="res-2075"><b>Proposed resolution:</b></p>

<p><i>[2014-02-16 Issaquah: Resolved by paper <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3927.html">n3927</a>]</i></p>







</body>
</html>
