Changes between Version 31 and Version 32 of Concurrency


Ignore:
Timestamp:
Apr 13, 2006 2:05:46 PM (9 years ago)
Author:
simonmar@…
Comment:

add choice of IORef semantics

Legend:

Unmodified
Added
Removed
Modified
  • Concurrency

    v31 v32  
    7373'''Pros'''
    7474 * Simpler from the programmer's point of view: no yield, no
    75    worrying about latency.  "write code as if the current
     75   worrying about latency.  "write a thread as if the current
    7676   thread is the only one.".
    7777
     
    101101
    102102
    103 === 2. Syntax for foreign call annoatations. ===
     103=== 2. nomenclature for foreign call annoatations. ===
    104104
    105105'''2.1.''' choices for concurrent calls:
    106106
    107 '''2.1.a.''' we annotate concurrent calls with
    108 
    109   '''a.''' concurrent[[BR]]
    110   '''b.''' mayblock[[BR]]
    111   '''c.''' mightblock[[BR]]
    112   '''d.''' blocks[[BR]]
    113   '''e.''' longrunning[[BR]]
    114 
    115   '''Rationale''' for using the term "block": blocking is the main
    116   reason for wanting concurrent calls.  Concurrent calls allow the
    117   progress guarantee to be retained in the presence of a blocking
    118   foreign call.  A foreign call that just takes a long time is still
    119   making progress.
    120 
    121   '''Rationale''' for not using the term "block": the fact that the
    122   call blocks is immaterial, the property we want to provide is that
    123   it doesn't impede progress of other Haskell threads.  A long-running
    124   call is indistinguishable from a blocked call in terms of the
    125   progress of other threads.
    126 
    127   We often don't know whether a library call will block or not (it
    128   isn't documented), whereas saying a call should run concurrently
    129   with other threads is a choice the programmer can reasonably make.
     107'''2.1.a.''' we annotate concurrent calls:
     108
     109  a. concurrent
     110  b. mayblock
     111  c. mightblock
     112  d. blocks
     113  e. longrunning
     114
     115'''Rationale''' for using the term "block": blocking is the main
     116reason for wanting concurrent calls.  Concurrent calls allow
     117the progress guarantee to be retained in the presence of a
     118blocking foreign call.  A foreign call that just takes a long
     119time is still making progress.
     120
     121'''Rationale''' for not using the term "block": the fact that the
     122call blocks is immaterial, the property we want to provide is
     123that it doesn't impede progress of other Haskell threads.  A
     124long-running call is indistinguishable from a blocked call in
     125terms of the progress of other threads.
     126
     127We often don't know whether a library call will block or not
     128(it isn't documented), whereas saying a call should run
     129concurrently with other threads is a choice the programmer can
     130reasonably make.
    130131
    131132'''2.1.b.''' we annotate non concurrent calls:
    132133
    133   '''Rationale''' for annotating the non-concurrent calls: this is a
    134   performance issue.  It is always correct to make a concurrent call,
    135   but it might be more efficient to make a non-concurrent call if the
    136   call does not block.  An implementation might implement ''all''
    137   calls as concurrent, for simplicity.
    138 
    139   Against: John Meacham says "The FFI is inherently unsafe. We do not
    140   need to coddle the programer who is writing raw FFI code."
    141 
    142   '''a.''' nonconcurrent[[BR]]
    143   '''b.''' noblock[[BR]]
    144   '''c.''' returnsquickly[[BR]]
    145   '''d.''' fast[[BR]]
    146   '''e.''' quick[[BR]]
    147 
    148 [[BR]]
     134'''Rationale''' for annotating the non-concurrent calls: this is a
     135performance issue.  It is always correct to make a concurrent
     136call, but it might be more efficient to make a non-concurrent
     137call if the call does not block.  An implementation might
     138implement *all* calls as concurrent, for simplicity.
     139
     140Against: John Meacham says "The FFI is inherently unsafe. We
     141do not need to coddle the programer who is writing raw FFI
     142code."
     143
     144  a. nonconcurrent
     145  b. noblock
     146  c. returnsquickly
     147  d. fast
     148  e. quick
     149
    149150'''2.2.''' choices for non-reentrant calls:
    150151
    151   '''a.''' nonreentrant[[BR]]
    152   '''b.''' nocallback
    153 
    154   '''Rationale''' for annotating the non-reentrant calls, as opposed
    155   to the reentrant ones: we want the "safe" option to be the default
    156   (as in the FFI spec).
    157 
    158 [[BR]]   
     152  a. nonreentrant
     153  b. nocallback
     154       
     155'''Rationale''' for annotating the non-reentrant calls, as opposed
     156to the reentrant ones: we want the "safe" option to be the
     157default (as in the FFI spec).
     158   
    159159'''2.3.''' should we annotate foreign calls according to whether they need
    160160to access thread-local state (TLS) or not?
    161161
     162In favour: a call that doesn't need access to thread-local state,
     163called from a bound thread, can be executed much more quickly on
     164an implementation that doesn't run the Haskell thread directly on
     165the bound OS thread, because it doesn't need to context switch.
     166
     167Against: libraries that require TLS, eg. OpenGL, often have many
     168fast TLS-using functions.  So implementations that need the no-TLS
     169annotation in order to get good performance, will probably still
     170get poor performance from libraries that need TLS anyway.
     171
     172
     173=== 3. Semantics of IORefs ===
     174
     175{{{MVar}}} operations must be strictly ordered; that is, a thread must never
     176observe {{{MVar}}} operations performed by another thread out of order.
     177
     178We have a choice when it comes to {{{IORef}}}s, however.  (Note that
     179this only affects true multiprocessor implementations of concurrent
     180Haskell).
     181
     182'''3.a''' Specify a weak memory model, in which {{{IORef}}} updates
     183may be observed out of order, but specify that certain operations
     184(eg. {{{MVar}}} operations) constitute sequence points around which no
     185re-ordering may happen.
     186
     187'''3.b''' Specify a strong memory model in which no re-ordering is
     188observable.
     189
    162190'''Pros'''
    163  * a call that doesn't need access to thread-local state, called from a bound thread, can be executed much more quickly on an implementation that doesn't run the Haskell thread directly on the bound OS thread, because it doesn't need to context switch.
    164 
    165 '''Cons'''
    166  * libraries that require TLS, eg. OpenGL, often have many fast TLS-using functions.  So implementations that need the no-TLS annotation in order to get good performance, will probably still get poor performance from libraries that need TLS anyway.
     191 * Some processors provide this anyway (current generations of x86, x86-64)
     192
     193 * The implementation will require some synchronisation in any case in order to prevent threads from observing partially-written closures.  For example, if one thread builds a closure and writes its address into an {{{IORef}}}, there must be a write barrier (and possibly a read barrier depending on the CPU) to prevent other threads from following the pointer and not finding the closure at the end of it. This synchronisation may be enough to provide the strong memory model anyway.
     194
     195 * Strong memory models are easier to program with, and leave fewer possibilities for a program to behave unexpectedly on a different processor or Haskell implementation.
     196
    167197
    168198------------------------