home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 14 Text / 14-Text.zip / machdocs.zip / threads.doc < prev   
Internet Message Format  |  1993-02-26  |  36KB

  1. From Pa.dec.com!nobody Thu Feb 25 20:15:46 1993
  2. Return-Path: <Pa.dec.com!nobody>
  3. Received: by ukelele.GCR.COM (Smail3.1.28.1 #1)
  4.     id m0nRtg1-0001S1a; Thu, 25 Feb 93 20:15 EST
  5. Received: from inet-gw-2.pa.dec.com by uu5.psi.com (5.65b/4.0.071791-PSI/PSINet) via SMTP;
  6.         id AA01611 for spj@ukelele.GCR.COM; Thu, 25 Feb 93 19:09:51 -0500
  7. Received: by inet-gw-2.pa.dec.com; id AA28460; Thu, 25 Feb 93 16:09:55 -0800
  8. Date: Thu, 25 Feb 93 16:09:55 -0800
  9. Message-Id: <9302260009.AA28460@inet-gw-2.pa.dec.com>
  10. From: "ftpmail service on inet-gw-2.pa.dec.com" <nobody@Pa.dec.com>
  11. To: spj@ukelele.GCR.COM
  12. Subject: part 001 of /.0/Mach/doc/threads.doc (@gatekeeper.dec.com) [Mach Dox] (ascii, last)
  13. X-Complaints-To: ftpmail-admin@inet-gw-2.pa.dec.com
  14. X-Service-Address: ftpmail@inet-gw-2.pa.dec.com
  15. X-Job-Number: 730680718.24209
  16. Precedence: bulk
  17. Reply-To: <nobody@inet-gw-2.pa.dec.com>
  18. Content-Type: text
  19. Content-Length: 35350
  20. Status: RO
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.                                    C THREADS
  35.  
  36.                                 Eric C. Cooper
  37.                                Richard P. Draves
  38.  
  39.                         Department of Computer Science
  40.                           Carnegie Mellon University
  41.                         Pittsburgh, Pennsylvania 15213
  42.  
  43.                            Draft of 17 October 1988
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.                                    ABSTRACT
  59.  
  60. The C Threads package allows parallel programming in C under the MACH operating
  61. system.  The package provides multiple  threads  of  control  for  parallelism,
  62. shared  variables,  mutual  exclusion  for  critical  sections,  and  condition
  63. variables for synchronization of threads.
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73. This research was sponsored by the Defense Advanced  Research  Projects  Agency
  74. (DoD),  ARPA  order  4864,  monitored  by  the  Space and Naval Warfare Systems
  75. Command under contract N00039-84-C-0467.
  76.  
  77. The views and conclusions contained in this document are those of  the  authors
  78. and  should  not  be  interpreted  as  representing  official  policies, either
  79. expressed or implied, of the Defense Advanced Research Projects  Agency  or  of
  80. the U.S. Government.  
  81.  
  82. 1. Introduction
  83. MACH   provides   a  set  of  low-level,  language-independent  primitives  for
  84. manipulating threads of control [3].  The  C  Threads  package  is  a  run-time
  85. library  that  provides  a  C  language interface to these facilities [1].  The
  86. constructs provided are similar to those found in Mesa [4]  and  Modula-2+ [5]:
  87. forking  and  joining  of  threads,  protection  of critical regions with mutex
  88. variables, and synchronization by means of condition variables.
  89.  
  90. 2. Naming Conventions
  91. An attempt has  been  made  to  use  a  consistent  style  of  naming  for  the
  92. abstractions  implemented  by  the  C  Threads package.  All types, macros, and
  93. functions implementing a given abstract data type are prefixed  with  the  type
  94. name and an underscore.  The name of the type itself is suffixed with _t and is
  95. defined via a C typedef.  Documentation of the form
  96.  
  97.                     typedef struct mutex {...} *mutex_t;
  98.  
  99. indicates that the mutex_t type is defined as a  pointer  to  a  referent  type
  100. struct mutex which may itself be useful to the programmer.  (In cases where the
  101. referent type should be considered opaque, documentation such as
  102.  
  103.                     typedef ... cthread_t;
  104.  
  105. is used instead.)
  106.  
  107. Continuing the example of the mutex_t type,  the  functions  mutex_alloc()  and
  108. mutex_free()   provide  dynamic  storage  allocation  and  deallocation.    The
  109. functions   mutex_init()   and   mutex_clear()   provide   initialization   and
  110. finalization  of  the  referent  type.    These  functions  are  useful  if the
  111. programmer wishes to include the referent type itself (rather than  a  pointer)
  112. in  a larger structure, for more efficient storage allocation.  They should not
  113. be  called  on  objects  that  are  dynamically  allocated  via  mutex_alloc().
  114. Type-specific  functions  such  as  mutex_lock()  and  mutex_unlock()  are also
  115. defined, of course.
  116.  
  117. 3. Initializing the C Threads Package
  118.  
  119.  
  120.  
  121. 3.1. cthreads.h
  122.  
  123.     #include <cthreads.h>
  124.  
  125. The header file cthreads.h defines the C threads interface.  All programs using
  126. C threads must include this file.
  127.  
  128.  
  129.  
  130. 3.2. cthread_init
  131.  
  132.     void
  133.     cthread_init()
  134.  
  135. The  cthread_init()  procedure  initializes  the  C  threads implementation.  A
  136. program using C threads must explicitly  call  cthread_init()  (typically  from
  137. main())  before  using  any  of  the other functions described below.  Multiple
  138. calls to cthread_init() are harmless.
  139.  
  140. 4. Threads of Control
  141.  
  142.  
  143.  
  144. 4.1. Creation
  145. When a C program starts, it contains  a  single  thread  of  control,  the  one
  146. executing  main().    The  thread  of  control is an active entity, moving from
  147. statement to statement, calling and returning from procedures.  New threads are
  148. created by fork operations.
  149.  
  150. Forking  a new thread of control is similar to calling a procedure, except that
  151. the caller does not wait for the procedure to  return.    Instead,  the  caller
  152. continues  to  execute  in  parallel with the execution of the procedure in the
  153. newly forked thread.  At some later time, the caller may rendez-vous  with  the
  154. thread  and  retrieve  its result (if any) by means of a join operation, or the
  155. caller may detach the newly created thread to assert that no thread  will  ever
  156. be interested in joining it.
  157.  
  158.  
  159.  
  160. 4.2. Termination
  161. A  thread  t  terminates  when  it  returns from the top-level procedure it was
  162. executing.[Currently, this is not true of the initial thread executing  main().
  163. Instead, an implicit call to exit() occurs when main() returns, terminating the
  164. entire program.    If  the  programmer  wishes  detached  threads  to  continue
  165. executing,  the  final statement of main() should be a call to cthread_exit().]
  166. If t has not been detached, it remains in limbo  until  another  thread  either
  167. joins it or detaches it; if t has been detached, no rendez-vous is necessary.
  168.  
  169.  
  170.  
  171. 4.3. cthread_fork
  172.  
  173.     typedef ... any_t;
  174.     typedef ... cthread_t;
  175.  
  176. The  any_t  type  represents a pointer to any C type.  The cthread_t type is an
  177. integer-size ``handle'' that uniquely identifies a thread of control.    Values
  178. of type cthread_t will be referred to as thread identifiers.
  179.  
  180.     cthread_t
  181.     cthread_fork(func, arg)
  182.             any_t (*func)();
  183.             any_t arg;
  184.  
  185. The cthread_fork() procedure creates a new thread of control in which func(arg)
  186. is executed concurrently with the caller's thread.  This is the sole  means  of
  187. creating  new  threads.    Arguments  larger  than  a pointer must be passed by
  188. reference.  Similarly, multiple  arguments  must  be  simulated  by  passing  a
  189. pointer   to   a   structure  containing  several  components.    The  call  to
  190. cthread_fork() returns a thread identifier that can be passed to cthread_join()
  191. or  cthread_detach()  (see  below).    Every  thread  must  be either joined or
  192. detached exactly once.
  193.  
  194.  
  195.  
  196. 4.4. cthread_exit
  197.  
  198.     void
  199.     cthread_exit(result)
  200.             any_t result;
  201.  
  202. This  procedure  causes  termination  of  the  calling  thread.    An  implicit
  203. cthread_exit()  occurs  when the top-level function of a thread returns, but it
  204. may also be called explicitly.  The result will be passed to  the  thread  that
  205. joins the caller, or discarded if the caller is detached.
  206.  
  207.  
  208.  
  209. 4.5. cthread_join
  210.  
  211.     any_t
  212.     cthread_join(t)
  213.             cthread_t t;
  214.  
  215. This  function  suspends the caller until the specified thread t terminates via
  216. cthread_exit().  (It follows that attempting to  join  one's  own  thread  will
  217. result  in  deadlock.)   The caller receives either the result of t's top-level
  218. function or the argument with which t explicitly called cthread_exit().
  219.  
  220.  
  221.  
  222. 4.6. cthread_detach
  223.  
  224.     void
  225.     cthread_detach(t)
  226.             cthread_t t;
  227.  
  228. The detach operation is used to indicate that the given thread  will  never  be
  229. joined.    This  is usually known at the time the thread is forked, so the most
  230. efficient usage is the following:
  231.  
  232.             cthread_detach(cthread_fork(procedure, argument));
  233.  
  234. A thread may, however, be detached at any time after it is forked, as  long  as
  235. no other attempt is made to join it or detach it.
  236.  
  237.  
  238.  
  239. 4.7. cthread_yield
  240.  
  241.     void
  242.     cthread_yield()
  243.  
  244. This  procedure  is  a  hint  to the scheduler, suggesting that this would be a
  245. convenient point to schedule another thread to run on  the  current  processor.
  246. Calls  to  cthread_yield() are unnecessary in an implementation with preemptive
  247. scheduling, but may be  required  to  avoid  starvation  in  a  coroutine-based
  248. implementation.
  249.  
  250.  
  251.  
  252. 4.8. cthread_self
  253.  
  254.     cthread_t
  255.     cthread_self()
  256.  
  257. This  function  returns  the  caller's own thread identifier, which is the same
  258. value that was returned by cthread_fork() to the creator of the  thread.    The
  259. thread  identifier  uniquely  identifies the thread, and hence may be used as a
  260. key in data structures that associate user data with individual threads.  Since
  261. thread  identifiers  may  be  reused  by  the  underlying  implementation,  the
  262. programmer should be careful to clean up such associations when threads exit.
  263.  
  264.  
  265.  
  266. 4.9. cthread_set_data, cthread_data
  267.  
  268.     void
  269.     cthread_set_data(t, data)
  270.             cthread_t t;
  271.             any_t data;
  272.  
  273.     any_t
  274.     cthread_data(t)
  275.             cthread_t t;
  276.  
  277. These functions allow the user to  associate  arbitrary  data  with  a  thread,
  278. providing  a  simple  form thread-specific ``global'' variable.  More elaborate
  279. mechanisms, such as per-thread property lists or hash tables, can then be built
  280. with these primitives.
  281.  
  282. 5. Synchronization
  283.  
  284.     typedef struct mutex {...} *mutex_t;
  285.  
  286.     typedef struct condition {...} *condition_t;
  287.  
  288. This  section describes mutual exclusion and synchronization primitives, called
  289. mutexes and condition variables.  In general,  these  primitives  are  used  to
  290. constrain  the  possible  interleavings  of  threads'  execution streams.  They
  291. separate the two most common uses of Dijkstra's P()  and  V()  operations  into
  292. distinct  facilities.   This approach basically implements monitors [2, 4], but
  293. without the syntactic sugar.
  294.  
  295. Mutually exclusive access to mutable data is necessary to prevent corruption of
  296. data.    As  simple  example,  consider  concurrent attempts to update a simple
  297. counter.  If  two  threads  fetch  the  current  value  into  a  (thread-local)
  298. register,  increment,  and write the value back in some order, the counter will
  299. only be incremented once, losing one thread's operation.  A mutex  solves  this
  300. problem by making the fetch-increment-deposit action atomic.  Before fetching a
  301. counter, a thread locks the associated mutex.  After depositing  a  new  value,
  302. the  thread unlocks the mutex.  If any other thread tries to use the counter in
  303. the meantime, it will block when it tries to lock the mutex.  If more than  one
  304. thread  tries  to  lock  the  mutex  at  the  same  time, the C threads package
  305. guarantees that only one will succeed; the rest will block.
  306.  
  307. Condition variables are used when one thread wants to wait until another thread
  308. has  finished doing something.  Every condition variable should be protected by
  309. a mutex.  Conceptually, the condition is a boolean function of the shared  data
  310. that  the  mutex protects.  Commonly, a thread locks the mutex and inspects the
  311. shared data.  If it doesn't like what it finds,  it  waits  using  a  condition
  312. variable.    This  operation  also temporarily unlocks the mutex, to give other
  313. threads a chance to get in and modify the shared data.  Eventually, one of them
  314. should  signal  the  condition  (which  wakes  up the blocked thread) before it
  315. unlocks the mutex.  At that point, the original thread will regain its lock and
  316. can  look  at  the shared data to see if things have improved.  It can't assume
  317. that it will like what it sees, because some other thread may have  slipped  in
  318. and mucked with the data after the the condition was signaled.
  319.  
  320. One  must take special care with data structures that are dynamically allocated
  321. and deallocated.  In particular, if the mutex that is controlling access  to  a
  322. dynamically  allocated  record  is part of the record, one must be sure that no
  323. thread is waiting for the mutex before freeing the record.
  324.  
  325. Attempting to lock a mutex that one already holds is another common error.  The
  326. offending  thread will block waiting for itself.  This can happen when a thread
  327. is traversing a complicated data structure, locking as it goes, and reaches the
  328. same  data  by  different  paths.  Another instance of this is when a thread is
  329. locking elements in an array, say to swap them, and it doesn't  check  for  the
  330. special case that the elements are the same.
  331.  
  332. In general, one must be very careful to avoid deadlock.  Deadlock is defined as
  333. the condition in which one or more threads are permanently blocked waiting  for
  334. each  other.   The above scenarios are a special case of deadlock.  The easiest
  335. way to avoid deadlock with mutexes  is  to  impose  a  total  ordering  on  the
  336. mutexes, and then ensure that threads only lock mutexes in increasing order.
  337.  
  338. One  important  issue the programmer must decide is what kind of granularity to
  339. use in protecting shared data with mutexes.  The two extremes are to  have  one
  340. mutex  protecting  all  shared  memory, and to have one mutex for every byte of
  341. shared memory.  Finer granularity normally increases the possible  parallelism,
  342. because  less  data  is locked at any one time.  However, it also increases the
  343. overhead lost to locking and unlocking mutexes and increases the possibility of
  344. deadlock.
  345.  
  346.  
  347.  
  348. 5.1. mutex_lock
  349.  
  350.     void
  351.     mutex_lock(m)
  352.             mutex_t m;
  353.  
  354. The  mutex_lock()  procedure  attempts  to lock the mutex m and blocks until it
  355. succeeds.  If several threads attempt to lock the same mutex concurrently,  one
  356. will  succeed,  and  the  others will block until m is unlocked.  The case of a
  357. thread attempting to lock  a  mutex  it  has  already  locked  is  not  treated
  358. specially; deadlock will result.
  359.  
  360.  
  361.  
  362. 5.2. mutex_try_lock
  363.  
  364.     int
  365.     mutex_try_lock(m)
  366.             mutex_t m;
  367.  
  368. The  mutex_try_lock() function attempts to lock the mutex m, like mutex_lock(),
  369. and  returns  TRUE  if  it  succeeds.    If  m  is  already  locked,   however,
  370. mutex_try_lock()  immediately returns FALSE rather than blocking.  For example,
  371. a busy-waiting version of the mutex_lock() procedure could be written in  terms
  372. of mutex_try_lock() as follows:
  373.  
  374.             void
  375.             mutex_lock(m)
  376.                     mutex_t m;
  377.             {
  378.                     for (;;)
  379.                             if (mutex_try_lock(m))
  380.                                     return;
  381.             }
  382.  
  383.  
  384.  
  385. 5.3. mutex_unlock
  386.  
  387.     void
  388.     mutex_unlock(m)
  389.             mutex_t m;
  390.  
  391. The mutex_unlock() procedure unlocks the mutex m, giving other threads a chance
  392. to lock it.
  393.  
  394.  
  395.  
  396. 5.4. condition_signal
  397.  
  398.     void
  399.     condition_signal(c)
  400.             condition_t c;
  401.  
  402. The condition_signal() procedure should be called when  one  thread  wishes  to
  403. indicate  that the condition represented by the condition variable is now true.
  404. If any other threads are waiting (via condition_wait()), then at least  one  of
  405. them will be awakened.  If no threads are waiting, then nothing happens.
  406.  
  407.  
  408.  
  409. 5.5. condition_broadcast
  410.  
  411.     void
  412.     condition_broadcast(c)
  413.             condition_t c;
  414.  
  415. The  condition_broadcast()  procedure  is similar to condition_signal(), except
  416. that it awakens all threads waiting for the condition, not just one of them.
  417.  
  418.  
  419.  
  420. 5.6. condition_wait
  421.  
  422.     void
  423.     condition_wait(c, m)
  424.             condition_t c;
  425.             mutex_t m;
  426.  
  427. The condition_wait() procedure unlocks m, suspends the calling thread until the
  428. specified  condition  is  likely  to be true, and locks m again when the thread
  429. resumes.  Since there is no guarantee that the condition will be true when  the
  430. thread resumes, use of this procedure should always be of the form
  431.  
  432.             mutex_lock(m);
  433.             ...
  434.             while (/* condition is not true */)
  435.                     condition_wait(c, m);
  436.             ...
  437.             mutex_unlock(m);
  438.  
  439. Shared variables should be inspected on each iteration to determine whether the
  440. condition is true.
  441.  
  442. 6. Management of Synchronization Variables
  443. A mutex or condition variable can be allocated dynamically from  the  heap,  or
  444. the  programmer  can  take  an  object  of  the  referent  type,  initialize it
  445. appropriately, and then use its address.
  446.  
  447.  
  448.  
  449. 6.1. Allocation
  450.  
  451.     mutex_t
  452.     mutex_alloc()
  453.  
  454.     condition_t
  455.     condition_alloc()
  456.  
  457. These functions provide dynamic allocation of mutex and condition objects.
  458.  
  459.  
  460.  
  461. 6.2. Deallocation
  462.  
  463.     void
  464.     mutex_free(m)
  465.             mutex_t m;
  466.  
  467.     void
  468.     condition_free(c)
  469.             condition_t c;
  470.  
  471. These functions allow the programmer to deallocate mutex and condition  objects
  472. that  were  allocated  dynamically.    Before  deallocating such an object, the
  473. programmer must  guarantee  that  no  other  thread  will  reference  it.    In
  474. particular,  a  thread  blocked  in  mutex_lock() or condition_wait() should be
  475. viewed as referencing the object continually, so freeing the object ``out  from
  476. under''  such  a thread is erroneous, and can result in bugs that are extremely
  477. difficult to track down.
  478.  
  479.  
  480.  
  481. 6.3. Initialization
  482.  
  483.     void
  484.     mutex_init(m)
  485.             struct mutex *m;
  486.  
  487.     void
  488.     condition_init(c)
  489.             struct condition *c;
  490.  
  491. These functions allow the programmer to initialize  an  object  of  the  struct
  492. mutex  or  struct  condition  referent  type,  so  that its address can be used
  493. wherever an object of type mutex_t or condition_t is expected.    For  example,
  494. the  mutex_alloc()  function  could  be  written  in  terms  of mutex_init() as
  495. follows:
  496.  
  497.             mutex_t
  498.             mutex_alloc()
  499.             {
  500.                     register mutex_t m;
  501.  
  502.                     m = (mutex_t) malloc(sizeof(struct mutex));
  503.                     mutex_init(m);
  504.                     return m;
  505.             }
  506.  
  507. Initialization of the referent type is most often used when the programmer  has
  508. included  the  referent  type  itself  (rather  than  a  pointer)  in  a larger
  509. structure, for more  efficient  storage  allocation.    For  instance,  a  data
  510. structure might contain a component of type struct mutex to allow each instance
  511. of that structure to be locked independently.   During  initialization  of  the
  512. instance, the programmer would call mutex_init() on the struct mutex component.
  513. The alternative  of  using  a  mutex_t  component  and  initializing  it  using
  514. mutex_alloc() would be less efficient.
  515.  
  516.  
  517.  
  518. 6.4. Finalization
  519.  
  520.     void
  521.     mutex_clear(m)
  522.             struct mutex *m;
  523.  
  524.     void
  525.     condition_clear(c)
  526.             struct condition *c;
  527.  
  528. These  functions allow the programmer to finalize an object of the struct mutex
  529. or struct condition referent type.  For  example,  the  mutex_free()  procedure
  530. could be written in terms of mutex_clear() as follows:
  531.  
  532.             void
  533.             mutex_free(m)
  534.                     mutex_t m;
  535.             {
  536.                     mutex_clear(m);
  537.                     free((char *) m);
  538.             }
  539.  
  540. 7. Shared Variables
  541. All  global  and  static  variables are shared among all threads: if one thread
  542. modifies such a variable, all other threads will observe the  new  value.    In
  543. addition,  a variable reachable from a pointer is shared among all threads that
  544. can dereference that pointer.  This  includes  objects  pointed  to  by  shared
  545. variables  of  pointer  type,  as  well  as  arguments  passed  by reference in
  546. cthread_fork().
  547.  
  548. When pointers are shared, some care is required  to  avoid  dangling  reference
  549. problems.    The programmer must ensure that the lifetime of the object pointed
  550. to is long enough to allow the other threads to dereference the pointer.  Since
  551. there  is  no  bound  on  the relative execution speed of threads, the simplest
  552. solution is to share pointers to global or heap-allocated objects only.   If  a
  553. pointer  to a local variable is shared, the procedure in which that variable is
  554. defined must remain active until it can be guaranteed that the pointer will  no
  555. longer  be dereferenced by other threads.  The synchronization functions can be
  556. used to ensure this.
  557.  
  558. The programmer must remember  that  unless  a  library,  like  the  standard  C
  559. library,  has  been  designed  to  work  in  the  presence  of  reentrancy, the
  560. operations provided by the library must be presumed to make unprotected use  of
  561. shared  data.   Hence, the programmer must protect against this through the use
  562. of a mutex that is locked before every library call  (or  sequence  of  library
  563. calls) and unlocked afterwards.
  564.  
  565.  
  566.  
  567. 7.1. Dynamic Allocation
  568. Dynamic  allocation  and  freeing  of user-defined data structures is typically
  569. accomplished with the standard C functions malloc() and free().  The C  threads
  570. package  provides  versions  of  these  functions  that  work  correctly in the
  571. presence of multiple threads.
  572.  
  573. 8. Using the C Threads Package
  574. All  of  the  functions  described  have  been   implemented   for   the   MACH
  575. multiprocessor   operating  system.    Three  implementations  of  threads  are
  576. provided, in the form of libraries.  Programs need not be recompiled to  use  a
  577. different thread implementation, only relinked.  To compile a program that uses
  578. C threads,  the  user  must  include  the  file  cthreads.h.    (The  directory
  579. /usr/mach/include  should  be  in  the  user's  CPATH  search  list  for  the C
  580. preprocessor to find this header file.)  The program must  call  cthread_init()
  581. before  using  any  other  C  threads  features.  To link a program that uses C
  582. threads, the user must specify  on  the  cc  command  line  one  of  the  three
  583. libraries  described  below,  followed  by  the -lmach library.  (The directory
  584. /usr/mach/lib should be in the user's LPATH search list for the linker to  find
  585. these libraries.)
  586.  
  587.  
  588.  
  589. 8.1. The Coroutine Implementation
  590. The  first  implementation,  -lco_threads, uses coroutines within a single MACH
  591. task (UNIX process).  Scheduling of  these  threads  is  non-preemptive,  hence
  592. cthread_yield()  should  be  called  within  loops  that  do not otherwise call
  593. synchronization procedures.  The  programmer  will  typically  link  with  this
  594. version while debugging.
  595.  
  596. This  implementation  includes  versions of the MACH interprocess communication
  597. primitives msg_receive(), msg_send(), and msg_rpc(), and a version of the  UNIX
  598. select()  system  call, that can be called from one thread without blocking the
  599. other threads in the program.  The other  forms  of  UNIX  I/O  have  not  been
  600. redefined  for  use with -lco_threads, however.  For example, calling getchar()
  601. from one thread may block all threads in the program, not just the caller.   To
  602. work  around  this,  the  programmer should first call select() on the relevant
  603. file descriptor to guarantee that  the  subsequent  input  operation  will  not
  604. block.
  605.  
  606.  
  607.  
  608. 8.2. The MACH Thread Implementation
  609. The second implementation, -lthreads, uses one MACH thread per C thread.  These
  610. threads  are  preemptively  scheduled,  and  may  execute  in  parallel  on   a
  611. multiprocessor.    This  is  the  implementation  that  should  be  used in the
  612. production version of a C threads program.
  613.  
  614. The  current  -lco_threads  and  -lthreads   implementations   allocate   large
  615. fixed-size  stacks  for  each  C thread in virtual memory.  The implementations
  616. rely on the MACH virtual memory system to  allocate  physical  memory  only  as
  617. needed by the thread.
  618.  
  619.  
  620.  
  621. 8.3. The MACH Task Implementation
  622. The third implementation, -ltask_threads, uses one MACH task (UNIX process) per
  623. thread, and uses the MACH virtual memory primitives  to  share  memory  between
  624. threads.    In  most circumstances, the -lthreads implementation should be used
  625. instead of this one.  An exception is when the programmer  wishes  to  use  the
  626. MACH  virtual  memory  primitives  to  provide  a specialized pattern of memory
  627. sharing between C threads.
  628.  
  629. Users of the -ltask_threads implementation should note that  capabilities  such
  630. as  MACH  ports  and UNIX file descriptors are private to the task that creates
  631. them, and so cannot be shared.  The current -ltask_threads implementation  also
  632. makes  stack  segments  private  to  each  task, so automatic (stack-allocated)
  633. variables cannot be shared.
  634.  
  635. The MACH operating system currently limits the number of tasks (and  hence  the
  636. number  of  C  threads  in  the  -ltask_threads implementation) that a user may
  637. create.  Applications that create  large  numbers  of  threads  will  encounter
  638. run-time  errors  when  they  exceed  this  limit.    It  may  be the case that
  639. concurrent  execution  is  required  to  avoid  deadlock  (for  example,  in  a
  640. multi-stage  pipeline).    For  applications  with largely independent threads,
  641. however, a limited degree of parallelism may  still  allow  correct  execution.
  642. The following function can be used in such applications.
  643.  
  644.     void
  645.     cthread_set_limit(n)
  646.             int n;
  647.  
  648. This  function  limits  the  number of active threads to n.  If a newly created
  649. thread of control exceeds this limit, it will not begin execution until another
  650. thread terminates.
  651.  
  652. 9. Debugging
  653. It   is   strongly   recommended   that   the   coroutine-based  implementation
  654. (-lco_threads) be used for debugging, for the following reasons:
  655.  
  656.    - The order of thread context switching  is  repeatable  in  successive
  657.      executions  of  the  program,  so obvious synchronization bugs may be
  658.      found easily.
  659.  
  660.    - Since the program is a single MACH task, existing  debuggers  can  be
  661.      used.
  662.  
  663.    - The user need not worry about concurrent calls to C library routines.
  664.  
  665.  
  666.  
  667. 9.1. Low-Level Tracing
  668.  
  669.     int cthread_debug;
  670.  
  671. Setting  this  variable  to  1 causes diagnostic information to be printed when
  672. each C threads primitive is executed.  Trace output appears on stdout.
  673.  
  674.  
  675.  
  676. 9.2. Associating Names with C Thread Objects
  677.  
  678.     void
  679.     cthread_set_name(t, name)
  680.             cthread_t t;
  681.             string_t name;
  682.  
  683.     string_t
  684.     cthread_name(t)
  685.             cthread_t t;
  686.  
  687.     void
  688.     mutex_set_name(m, name)
  689.             mutex_t m;
  690.             string_t name;
  691.  
  692.     string_t
  693.     mutex_name(m)
  694.             mutex_t m;
  695.  
  696.     void
  697.     condition_set_name(c, name)
  698.             condition_t c;
  699.             string_t name;
  700.  
  701.     string_t
  702.     condition_name(c)
  703.             condition_t c;
  704.  
  705. These functions allow the user to associate a name with  a  thread,  mutex,  or
  706. condition.    The name is used when trace information is displayed (see above).
  707. The  name  may  also  be  used  by  the  programmer  for   application-specific
  708. diagnostics.
  709.  
  710.  
  711.  
  712. 9.3. Pitfalls of Preemptively Scheduled Threads
  713. The  C  run-time library needs a substantial amount of modification in order to
  714. be used with preemptively scheduled  threads  (-lthreads  and  -ltask_threads).
  715. Currently  the  user  must  ensure  that  calls to the standard I/O library are
  716. serialized, through the use of one or  more  mutex  variables.    (The  storage
  717. allocation   functions   malloc()   and  free()  do  not  require  any  special
  718. precautions.)
  719.  
  720. The debuggers currently available under MACH cannot be used on programs  linked
  721. with  -lthreads  or  -ltask_threads.    Furthermore, the very act of turning on
  722. tracing or adding print statements may perturb programs that incorrectly depend
  723. on  thread  execution  speed.  One technique that is useful in such cases is to
  724. vary the granularity of locking and synchronization used in the program, making
  725. sure that the program works with coarse-grained synchronization before refining
  726. it further.
  727.  
  728. 10. Examples
  729. The following example illustrates how the facilities described here can be used
  730. to program Hoare monitors [2].  The program would be compiled and linked by the
  731. command
  732.  
  733.             cc hoaremonitor.c -lthreads -lmach
  734.  
  735.     /*
  736.      * Producer/consumer with bounded buffer.
  737.      *
  738.      * The producer reads characters from stdin
  739.      * and puts them into the buffer.  The consumer
  740.      * gets characters from the buffer and writes them
  741.      * to stdout.  The two threads execute concurrently
  742.      * except when synchronized by the buffer.
  743.      */
  744.     #include <stdio.h>
  745.     #include <cthreads.h>
  746.     typedef struct buffer {
  747.         struct mutex lock;
  748.         char *chars;      /* chars[0..size-1] */
  749.         int size;
  750.         int px, cx;       /* producer and consumer indices */
  751.         int count;        /* number of unconsumed chars in buffer */
  752.         struct condition non_empty, non_full;
  753.     } *buffer_t;
  754.     void
  755.     buffer_put(ch, b)
  756.         char ch;
  757.         buffer_t b;
  758.     {
  759.         mutex_lock(&b->lock);
  760.         while (b->count == b->size)
  761.             condition_wait(&b->non_full, &b->lock);
  762.         ASSERT(0 <= b->count && b->count < b->size);
  763.         b->chars[b->px] = ch;
  764.         b->px = (b->px + 1) % b->size;
  765.         b->count += 1;
  766.         condition_signal(&b->non_empty);
  767.         mutex_unlock(&b->lock);
  768.     }
  769.     char
  770.     buffer_get(b)
  771.         buffer_t b;
  772.     {
  773.         char ch;
  774.         mutex_lock(&b->lock);
  775.         while (b->count == 0)
  776.             condition_wait(&b->non_empty, &b->lock);
  777.         ASSERT(0 < b->count && b->count <= b->size);
  778.         ch = b->chars[b->cx];
  779.         b->cx = (b->cx + 1) % b->size;
  780.         b->count -= 1;
  781.         condition_signal(&b->non_full);
  782.         mutex_unlock(&b->lock);
  783.         return ch;
  784.     }
  785.     void
  786.     producer(b)
  787.         buffer_t b;
  788.     {
  789.         int ch;
  790.         do buffer_put((ch = getchar()), b);
  791.         while (ch != EOF);
  792.     }
  793.     void
  794.     consumer(b)
  795.         buffer_t b;
  796.     {
  797.         int ch;
  798.         while ((ch = buffer_get(b)) != EOF)
  799.             printf("%c", ch);
  800.     }
  801.     buffer_t
  802.     buffer_alloc(size)
  803.         int size;
  804.     {
  805.         buffer_t b;
  806.         extern char *malloc();
  807.         b = (buffer_t) malloc(sizeof(struct buffer));
  808.         mutex_init(&b->lock);
  809.         b->size = size;
  810.         b->chars = malloc((unsigned) size);
  811.         b->px = b->cx = b->count = 0;
  812.         condition_init(&b->non_empty);
  813.         condition_init(&b->non_full);
  814.         return b;
  815.     }
  816.     #define BUFFER_SIZE 10
  817.     main()
  818.     {
  819.         buffer_t b;
  820.         cthread_init();
  821.         b = buffer_alloc(BUFFER_SIZE);
  822.         cthread_detach(cthread_fork(producer, b));
  823.         cthread_detach(cthread_fork(consumer, b));
  824.         cthread_exit(0);
  825.     }
  826.  
  827. The following example shows how to structure a program in which a single master
  828. thread  spawns  a  number  of  concurrent  slaves and then waits until they all
  829. finish.  The program would be compiled and linked by the command
  830.  
  831.             cc masterslave.c -lthreads -lmach
  832.  
  833.     /*
  834.      * Master/slave program structure.
  835.      */
  836.     #include <stdio.h>
  837.     #include <cthreads.h>
  838.     int count;         /* number of slaves active */
  839.     mutex_t lock;      /* mutual exclusion for count */
  840.     condition_t done;  /* signalled each time a slave finishes */
  841.     extern long random();
  842.     init()
  843.     {
  844.         cthread_init();
  845.         count = 0;
  846.         lock = mutex_alloc();
  847.         done = condition_alloc();
  848.         srandom(time((int *) 0));  /* initialize random number generator */
  849.     }
  850.     /*
  851.      * Each slave just counts up to its argument,
  852.      * yielding the processor on each iteration.
  853.      * When it is finished, it decrements the global count
  854.      * and signals that it is done.
  855.      */
  856.     slave(n)
  857.         int n;
  858.     {
  859.         int i;
  860.         for (i = 0; i < n; i += 1)
  861.             cthread_yield();
  862.         mutex_lock(lock);
  863.         count -= 1;
  864.         printf("Slave finished %d cycles.\n", n);
  865.         condition_signal(done);
  866.         mutex_unlock(lock);
  867.     }
  868.     /*
  869.      * The master spawns a given number of slaves
  870.      * and then waits for them all to finish.
  871.      */
  872.     master(nslaves)
  873.         int nslaves;
  874.     {
  875.         int i;
  876.         for (i = 1; i <= nslaves; i += 1) {
  877.             mutex_lock(lock);
  878.             /*
  879.              * Fork a slave and detach it,
  880.              * since the master never joins it individually.
  881.              */
  882.             count += 1;
  883.             cthread_detach(cthread_fork(slave, random() % 1000));
  884.             mutex_unlock(lock);
  885.         }
  886.         mutex_lock(lock);
  887.         while (count != 0)
  888.             condition_wait(done, lock);
  889.         mutex_unlock(lock);
  890.         printf("All %d slaves have finished.\n", nslaves);
  891.         cthread_exit(0);
  892.     }
  893.     main()
  894.     {
  895.         init();
  896.         master((int) random() % 16);  /* create up to 15 slaves */
  897.     }
  898.  
  899.                                   REFERENCES
  900.  
  901.  
  902. [1]   Brian W. Kernighan and Dennis M. Ritchie.
  903.       The C Programming Language.
  904.       Prentice-Hall, 1978.
  905.  
  906.  
  907. [2]   C. A. R. Hoare.
  908.       Monitors: An Operating System Structuring Concept.
  909.       Communications of the ACM 17(10):549-557, October, 1974.
  910.  
  911.  
  912. [3]   Robert V. Baron, Richard F. Rashid, Ellen Siegel, Avadis Tevanian, and
  913.       Michael W. Young.
  914.       MACH-1: A Multiprocessor Oriented Operating System and Environment.
  915.       In Arthur Wouk (editor), New Computing Environments: Parallel, Vector,
  916.          and Symbolic. SIAM, 1986.
  917.  
  918.  
  919. [4]   Butler W. Lampson and David D. Redell.
  920.       Experience with Processes and Monitors in Mesa.
  921.       Communications of the ACM 23(2):105-117, February, 1980.
  922.  
  923.  
  924. [5]   Paul Rovner, Roy Levin, and John Wick.
  925.       On Extending Modula-2 for Building Large, Integrated Systems.
  926.       Technical Report 3, DEC Systems Research Center, January, 1985.
  927.  
  928.                                Table of Contents
  929. 1. Introduction                                                               1
  930. 2. Naming Conventions                                                         1
  931. 3. Initializing the C Threads Package                                         1
  932.      3.1. cthreads.h                                                          1
  933.      3.2. cthread_init                                                        1
  934. 4. Threads of Control                                                         1
  935.      4.1. Creation                                                            1
  936.      4.2. Termination                                                         1
  937.      4.3. cthread_fork                                                        1
  938.      4.4. cthread_exit                                                        1
  939.      4.5. cthread_join                                                        1
  940.      4.6. cthread_detach                                                      1
  941.      4.7. cthread_yield                                                       1
  942.      4.8. cthread_self                                                        1
  943.      4.9. cthread_set_data, cthread_data                                      1
  944. 5. Synchronization                                                            2
  945.      5.1. mutex_lock                                                          2
  946.      5.2. mutex_try_lock                                                      2
  947.      5.3. mutex_unlock                                                        2
  948.      5.4. condition_signal                                                    2
  949.      5.5. condition_broadcast                                                 2
  950.      5.6. condition_wait                                                      2
  951. 6. Management of Synchronization Variables                                    2
  952.      6.1. Allocation                                                          2
  953.      6.2. Deallocation                                                        2
  954.      6.3. Initialization                                                      3
  955.      6.4. Finalization                                                        3
  956. 7. Shared Variables                                                           3
  957.      7.1. Dynamic Allocation                                                  3
  958. 8. Using the C Threads Package                                                3
  959.      8.1. The Coroutine Implementation                                        3
  960.      8.2. The MACH Thread Implementation                                      3
  961.      8.3. The MACH Task Implementation                                        3
  962. 9. Debugging                                                                  3
  963.      9.1. Low-Level Tracing                                                   3
  964.      9.2. Associating Names with C Thread Objects                             4
  965.      9.3. Pitfalls of Preemptively Scheduled Threads                          4
  966. 10. Examples                                                                  5
  967.  
  968.