Changes between Version 31 and Version 32 of Concurrency


Ignore:
Timestamp:
Apr 13, 2006 2:05:46 PM (8 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------------------------