cml.texi 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. @node Concurrent ML
  2. @section Concurrent ML
  3. @cindex rendezvous
  4. @cindex event
  5. Scheme48 provides a high-level event synchronization facility based on
  6. on Reppy's @dfn{Concurrent ML} [Reppy 99]. The primary object in CML
  7. is the @dfn{rendezvous}@footnote{In the original CML, these were called
  8. @dfn{events}, but that term was deemed too overloaded and confusing
  9. when Scheme48's library was developed.}, which represents a point of
  10. process synchronization. A rich library for manipulating rendezvous
  11. and several useful, high-level synchronization abstractions are built
  12. atop rendezvous.
  13. @menu
  14. * Rendezvous concepts::
  15. * Rendezvous base combinators::
  16. * Rendezvous communication channels::
  17. * Rendezvous-synchronized cells::
  18. * Concurrent ML to Scheme correspondence::
  19. @end menu
  20. @node Rendezvous concepts
  21. @subsection Rendezvous concepts
  22. When access to a resource must be synchronized between multiple
  23. processes, for example to transmit information from one process to
  24. another over some sort of communication channel, the resource provides
  25. a @dfn{rendezvous} to accomplish this, which represents a potential
  26. point of synchronization between processes. The use of rendezvous
  27. occurs in two stages: @dfn{synchronization} and @dfn{enablement}. Note
  28. that creation of rendezvous is an unrelated matter, and it does not (or
  29. should not) itself result in any communication or synchronization
  30. between processes.
  31. When a process requires an external resource for which it has a
  32. rendezvous, it @dfn{synchronizes} that rendezvous. This first polls
  33. whether the resource is immediately available; if so, the rendezvous is
  34. already @dfn{enabled}, and a value from the resource is immediately
  35. produced from the synchronization. Otherwise, the synchronization of
  36. the rendezvous is recorded somehow externally, and the process is
  37. blocked until the rendezvous is enabled by an external entity, usually
  38. one that made the resource available. Rendezvous may be re@"used
  39. arbitrarily many times; the value produced by an enabled, synchronized
  40. rendezvous is not cached. Note, however, that the construction of a
  41. rendezvous does not (or should not) have destructive effect, such as
  42. sending a message to a remote server or locking a mutex; the only
  43. destructive effects should be incurred at synchronization or enablement
  44. time. For effecting initialization prior to the synchronization of a
  45. rendezvous, see below on @dfn{delayed rendezvous}.
  46. Rendezvous may consist of multiple rendezvous choices, any of which may
  47. be taken when enabled but only one of which actually is. If, when a
  48. composite rendezvous is initially synchronized, several components are
  49. immediately enabled, each one has a particular numeric priority which
  50. is used to choose among them. If several are tied for the highest
  51. priority, a random one is chosen. If none is enabled when the choice
  52. is synchronized, however, the synchronizer process is suspended until
  53. the first one is enabled and revives the process. When this happens,
  54. any or all of the other rendezvous components may receive a negative
  55. acknowledgement; see below on @dfn{delayed rendezvous with negative
  56. acknowledgement}.
  57. A rendezvous may also be a rendezvous @dfn{wrapped} with a procedure,
  58. which means that, when the internal rendezvous becomes enabled, the
  59. wrapper one also becomes enabled, and the value it produces is the
  60. result of applying its procedure to the value that the internal
  61. rendezvous produced. This allows the easy composition of complex
  62. rendezvous from simpler ones, and it also provides a simple mechanism
  63. for performing different actions following the enablement of different
  64. rendezvous, rather than conflating the results of several possible
  65. rendezvous choices into one value and operating on that (though this,
  66. too, can be a useful operation).
  67. @subsection Delayed rendezvous
  68. A rendezvous may be @dfn{delayed}, which means that its synchronization
  69. requires some processing that could not or would not be reasonable to
  70. perform at its construction. It consists of a nullary procedure to
  71. generate the actual rendezvous to synchronize when the delayed
  72. rendezvous is itself synchronized.
  73. For example, a rendezvous for generating unique identifiers, by sending
  74. a request over a network to some server and waiting for a response,
  75. could not be constructed by waiting for a response from the server,
  76. because that may block, which should not occur until synchronization.
  77. It also could not be constructed by first sending a request to the
  78. server at all, because that would have a destructive effect, which is
  79. not meant to happen when creating a rendezvous, only when synchronizing
  80. or enabling one.
  81. Instead, the unique identifier rendezvous would be implemented as a
  82. delayed rendezvous that, when synchronized, would send a request to
  83. the server and generate a rendezvous for the actual synchronization
  84. that would become enabled on receiving the server's response.
  85. @subsubsection Negative acknowledgements
  86. Delayed rendezvous may also receive negative acknowledgements. Rather
  87. than a simple nullary procedure being used to generate the actual
  88. rendezvous for synchronization, the procedure is unary, and it is
  89. passed a @dfn{negative acknowledgement rendezvous}, or @dfn{nack} for
  90. short. This nack is enabled if the actual rendezvous was not chosen
  91. among a composite group of rendezvous being synchronized. This allows
  92. not only delaying initialization of rendezvous until necessary but also
  93. aborting or rescinding initialized transactions if their rendezvous are
  94. unchosen and therefore unused.
  95. For example, a complex database query might be the object of some
  96. rendezvous, but it is pointless to continue constructing the result if
  97. that rendezvous is not chosen. A nack can be used to prematurely abort
  98. the query to the database if another rendezvous was chosen in the stead
  99. of that for the database query.
  100. @node Rendezvous base combinators
  101. @subsection Rendezvous combinators
  102. @stindex rendezvous
  103. The @code{rendezvous} structure exports several basic rendezvous
  104. combinators.
  105. @defvr Constant never-rv @returns{} rendezvous
  106. A rendezvous that is never enabled. If synchronized, this will block
  107. the synchronizing thread indefinitely.
  108. @end defvr
  109. @deffn procedure always-rv value @returns{} rendezvous
  110. Returns a rendezvous that is always enabled with the given value. This
  111. rendezvous will never block the synchronizing thread.
  112. @end deffn
  113. @deffn procedure guard rv-generator @returns{} rendezvous
  114. @deffnx procedure with-nack rv-generator @returns{} rendezvous
  115. @code{Guard} returns a delayed rendezvous, generated by the given
  116. procedure @var{rv-generator}, which is passed zero arguments whenever
  117. the resultant rendezvous is synchronized. @code{With-nack} returns a
  118. delayed rendezvous for which a negative acknowledgement rendezvous is
  119. constructed. If the resultant rendezvous is synchronized as a part of
  120. a composite rendezvous, the procedure @code{rv-generator} is passed a
  121. nack for the synchronization, and it returns the rendezvous to actually
  122. synchronize. If the delayed rendezvous was synchronized as part of a
  123. composite group of rendezvous, and another rendezvous among that group
  124. is enabled and chosen first, the nack is enabled.
  125. @end deffn
  126. @deffn procedure choose rendezvous @dots{} @returns{} composite-rendezvous
  127. Returns a rendezvous that, when synchronized, synchronizes all of the
  128. given components, and chooses only the first one to become enabled, or
  129. the highest priority one if there are any that are already enabled. If
  130. any of the rendezvous that were not chosen when the composite became
  131. enabled were delayed rendezvous with nacks, their nacks are enabled.
  132. @end deffn
  133. @deffn procedure wrap rendezvous procedure @returns{} rendezvous
  134. Returns a rendezvous equivalent to @var{rendezvous} but wrapped with
  135. @var{procedure}, so that, when the resultant rendezvous is
  136. synchronized, @var{rendezvous} is transitively synchronized, and when
  137. @var{rendezvous} is enabled, the resultant rendezvous is also enabled,
  138. with the value that @var{procedure} returns when passed the value
  139. produced by @var{rendezvous}.
  140. @lisp
  141. (sync (wrap (always-rv 4)
  142. (lambda (x) (* x x)))) @returns{} 16@end lisp
  143. @end deffn
  144. @deffn procedure sync rendezvous @returns{} value (may block)
  145. @deffnx procedure select rendezvous @dots{} @returns{} value (may block)
  146. @code{Sync} and @code{select} synchronize rendezvous. @code{Sync}
  147. synchronizes a single one; @code{select} synchronizes any from the
  148. given set of them. @code{Select} is equivalent to @code{(sync (apply
  149. choose @var{rendezvous @dots{}}))}, but it may be implemented more
  150. efficiently.
  151. @end deffn
  152. @subsubsection Timing rendezvous
  153. @cindex time
  154. @stindex rendezvous-time
  155. The @code{rendezvous-time} structure exports two constructors for
  156. rendezvous that become enabled only at a specific time or after a delay
  157. in time.
  158. @deffn procedure at-real-time-rv milliseconds @returns{} rendezvous
  159. @deffnx procedure after-time-rv milliseconds @returns{} rendezvous
  160. @code{At-real-time-rv} returns a rendezvous that becomes enabled at the
  161. time @var{milliseconds} relative to the start of the Scheme program.
  162. @code{After-time-rv} returns a rendezvous that becomes enabled at least
  163. @var{milliseconds} after synchronization (@emph{not} construction).
  164. @end deffn
  165. @node Rendezvous communication channels
  166. @subsection Rendezvous communication channels
  167. @subsubsection Synchronous channels
  168. @cindex channels
  169. @cindex synchronous channels
  170. @cindex message-passing
  171. @stindex rendezvous-channels
  172. The @code{rendezvous-channels} structure provides a facility for
  173. @dfn{synchronous channels}: channels for communication between threads
  174. such that any receiver blocks until another thread sends a message, or
  175. any sender blocks until another thread receives the sent message. In
  176. CML, synchronous channels are also called merely `channels.'
  177. @deffn procedure make-channel @returns{} channel
  178. @deffnx procedure channel? object @returns{} boolean
  179. @code{Make-channel} creates and returns a new channel. @code{Channel?}
  180. is the disjoint type predicate for channels.
  181. @end deffn
  182. @deffn procedure send-rv channel message @returns{} rendezvous
  183. @deffnx procedure send channel message @returns{} unspecified (may block)
  184. @code{Send-rv} returns a rendezvous that, when synchronized, becomes
  185. enabled when a reception rendezvous for @var{channel} is synchronized,
  186. at which point that reception rendezvous is enabled with a value of
  187. @var{message}. When enabled, the rendezvous returned by @code{send-rv}
  188. produces an unspecified value. @code{Send} is like @code{send-rv}, but
  189. it has the effect of immediately synchronizing the rendezvous, so it
  190. therefore may block, and it does not return a rendezvous; @code{(send
  191. @var{channel} @var{message})} is equivalent to @code{(sync (send-rv
  192. @var{channel} @var{message}))}.
  193. @end deffn
  194. @deffn procedure receive-rv channel @returns{} rendezvous
  195. @deffnx procedure receive channel @returns{} value (may block)
  196. @code{Receive-rv} returns a rendezvous that, when synchronized, and
  197. when a sender rendezvous for @var{channel} with some message is
  198. synchronized, becomes enabled with that message, at which point the
  199. sender rendezvous is enabled with an unspecified value. @code{Receive}
  200. is like @code{receive-rv}, but it has the effect of immediately
  201. synchronizing the reception rendezvous, so it therefore may block, and
  202. it does not return the rendezvous but rather the message that was sent;
  203. @code{(receive @var{channel})} is equivalent to @code{(sync (receive-rv
  204. @var{channel}))}.
  205. @end deffn
  206. @subsubsection Asynchronous channels
  207. @cindex channels
  208. @cindex asynchronous channels
  209. @cindex message-passing
  210. @stindex rendezvous-async-channels
  211. The @code{rendezvous-async-channels} provides an @dfn{asynchronous
  212. channel}@footnote{Known as @dfn{mailboxes} in Reppy's original CML.}
  213. facility. Like synchronous channels, any attempts to read from an
  214. asynchronous channel will block if there are no messages waiting to be
  215. read. Unlike synchronous channels, however, sending a message will
  216. never block. Instead, a queue of messages or a queue of recipients is
  217. maintained: if a message is sent and there is a waiting recipient, the
  218. message is delivered to that recipient; otherwise it is added to the
  219. queue of messages. If a thread attempts to receive a message from an
  220. asynchronous channel and there is a pending message, it receives that
  221. message; otherwise it adds itself to the list of waiting recipients and
  222. then blocks.
  223. @strong{Note:} Operations on synchronous channels from the structure
  224. @code{rendezvous-channels} do not work on asynchronous channels.
  225. @deffn procedure make-async-channel @returns{} async-channel
  226. @deffnx procedure async-channel? obj @returns{} boolean
  227. @code{Make-async-channel} creates and returns an asynchronous channel.
  228. @code{Async-channel?} is the disjoint type predicate for asynchronous
  229. channels.
  230. @end deffn
  231. @deffn procedure receive-async-rv channel @returns{} rendezvous
  232. @deffnx procedure receive-async channel @returns{} value (may block)
  233. @code{Receive-async-rv} returns a rendezvous that, when synchronized,
  234. becomes enabled when a message is available in @var{channel}'s queue of
  235. messages. @code{Receive-async} has the effect of immediately
  236. synchronizing such a rendezvous and, when the rendezvous becomes
  237. enabled, returning the value itself, rather than the rendezvous;
  238. @code{(receive-async @var{channel})} is equivalent to @code{(sync
  239. (receive-async-rv @var{channel}))}.
  240. @end deffn
  241. @deffn procedure send-async channel message @returns{} unspecified
  242. Sends a message to the asynchronous channel @var{channel}. Unlike the
  243. synchronous channel @code{send} operation, this procedure never blocks
  244. arbitrarily long.@footnote{However, asynchronous channels are
  245. implemented by a thread that manages two synchronous channels (one for
  246. sends & one for receives), so this may block briefly if the thread is
  247. busy receiving other send or receive requests.} There is, therefore,
  248. no need for a @code{send-async-rv} like the @code{send-rv} for
  249. synchronous channels. If there is a waiting message recipient, the
  250. message is delivered to that recipient; otherwise, it is added to the
  251. channel's message queue.
  252. @end deffn
  253. @node Rendezvous-synchronized cells
  254. @subsection Rendezvous-synchronized cells
  255. @subsubsection Placeholders: single-assignment cells
  256. @stindex rendezvous-placeholders
  257. @dfn{Placeholders}@footnote{Called @dfn{I-variables} in Reppy's CML,
  258. and @dfn{I-structures} in ID-90.} are single-assignment cells on which
  259. readers block until they are assigned.
  260. @strong{Note:} These placeholders are disjoint from and incompatible
  261. with the placeholder mechanism provided in the @code{placeholders}
  262. structure, and attempts to apply operations on one to values of the
  263. other are errors.
  264. @deffn procedure make-placeholder [id] @returns empty placeholder
  265. @deffnx procedure placeholder? object @returns{} boolean
  266. @code{Make-placeholder} creates and returns a new, empty placeholder.
  267. @var{Id} is used only for debugging purposes; it is included in the
  268. printed representation of the placeholder. @code{Placeholder?} is the
  269. disjoint type predicate for placeholders.
  270. @end deffn
  271. @deffn procedure placeholder-value-rv placeholder @returns{} rendezvous
  272. @deffnx procedure placeholder-value placeholder @returns{} value (may block)
  273. @code{Placeholder-value-rv} returns a rendezvous that, when
  274. synchronized, becomes enabled when @var{placeholder} has a value, with
  275. that value. @code{Placeholder-value} has the effect of immediately
  276. synchronizing such a rendezvous, and it returns the value directly, but
  277. possibly after blocking.
  278. @end deffn
  279. @deffn procedure placeholder-set! placeholder value @returns{} unspecified
  280. Sets @var{placeholder}'s value to be @var{value}, and enables all
  281. rendezvous for @var{placeholder}'s value with that value. It is an
  282. error if @var{placeholder} has already been assigned.
  283. @end deffn
  284. @subsubsection Jars: multiple-assignment cells
  285. @stindex rendezvous-jars
  286. @dfn{Jars}@footnote{Termed @dfn{M-variables} in Reppy's CML.} are
  287. multiple-assignment cells on which readers block. Reading from a full
  288. jar has the effect of emptying it, enabling the possibility of
  289. subsequent assignment, unlike placeholders; and jars may be assigned
  290. multiple times, but, like placeholders, only jars that are empty may be
  291. assigned.
  292. @deffn procedure make-jar [id] @returns{} empty jar
  293. @deffnx procedure jar? object @returns{} boolean
  294. @code{Make-jar} creates and returns a new, empty jar. @var{Id} is used
  295. only for debugging purposes; it is included in the printed
  296. representation of the jar. @code{Jar?} is the disjoint type predicate
  297. for jars.
  298. @end deffn
  299. @deffn procedure jar-take-rv jar @returns{} rendezvous
  300. @deffnx procedure jar-take jar @returns{} value (may block)
  301. @code{Jar-take-rv} returns a rendezvous that, when synchronized,
  302. becomes enabled when @var{jar} has a value, which is what value the
  303. rendezvous becomes enabled with; when that rendezvous is enabled, it
  304. also removes the value from @var{jar}, putting the jar into an empty
  305. state. @code{Jar-take} has the effect of synchronizing such a
  306. rendezvous, may block because of that, and returns the value of the jar
  307. directly, not a rendezvous.
  308. @end deffn
  309. @deffn procedure jar-put! jar value @returns{} unspecified
  310. @code{Jar-put!} puts @var{value} into the empty jar @var{jar}. If any
  311. taker rendezvous are waiting, the first is enabled with the value, and
  312. the jar is returned to its empty state; otherwise, the jar is put in
  313. the full state. @code{Jar-put!} is an error if applied to a full jar.
  314. @end deffn
  315. @node Concurrent ML to Scheme correspondence
  316. @subsection Concurrent ML to Scheme correspondence
  317. @multitable {structure @code{SyncVar}} {(no equivalent; use @code{spawn} and @code{lambda})}
  318. @item CML name @tab Scheme name
  319. @item structure @code{CML} @tab structure @code{threads}
  320. @item @code{version} @tab (no equivalent)
  321. @item @code{banner} @tab (no equivalent)
  322. @item @code{spawnc} @tab (no equivalent; use @code{spawn} and @code{lambda})
  323. @item @code{spawn} @tab @code{spawn}
  324. @item @code{yield} @tab @code{relinquish-timeslice}
  325. @item @code{exit} @tab @code{terminate-current-thread}
  326. @item @code{getTid} @tab @code{current-thread}
  327. @item @code{sameTid} @tab @code{eq?} (R5RS)
  328. @item @code{tidToString} @tab (no equivalent; use the writer)
  329. @item @tab structure @code{threads-internal}
  330. @item @code{hashTid} @tab @code{thread-uid}
  331. @item @tab structure @code{rendezvous}
  332. @item @code{wrap} @tab @code{wrap}
  333. @item @code{guard} @tab @code{guard}
  334. @item @code{withNack} @tab @code{with-nack}
  335. @item @code{choose} @tab @code{choose}
  336. @item @code{sync} @tab @code{sync}
  337. @item @code{select} @tab @code{select}
  338. @item @code{never} @tab @code{never-rv}
  339. @item @code{alwaysEvt} @tab @code{always-rv}
  340. @item @code{joinEvt} @tab (no equivalent)
  341. @item @tab structure @code{rendezvous-channels}
  342. @item @code{channel} @tab @code{make-channel}
  343. @item @code{sameChannel} @tab @code{eq?} (R5RS)
  344. @item @code{send} @tab @code{send}
  345. @item @code{recv} @tab @code{receive}
  346. @item @code{sendEvt} @tab @code{send-rv}
  347. @item @code{recvEvt} @tab @code{receive-rv}
  348. @item @code{sendPoll} @tab (no equivalent)
  349. @item @code{recvPoll} @tab (no equivalent)
  350. @item @tab structure @code{rendezvous-time}
  351. @item @code{timeOutEvt} @tab @code{after-time-rv}
  352. @item @code{atTimeEvt} @tab @code{at-real-time-rv}
  353. @item structure @code{SyncVar} @tab structure @code{rendezvous-placeholders}
  354. @item exception @code{Put} @tab (no equivalent)
  355. @item @code{iVar} @tab @code{make-placeholder}
  356. @item @code{iPut} @tab @code{placeholder-set!}
  357. @item @code{iGet} @tab @code{placeholder-value}
  358. @item @code{iGetEvt} @tab @code{placeholder-value-rv}
  359. @item @code{iGetPoll} @tab (no equivalent)
  360. @item @code{sameIVar} @tab @code{eq?} (R5RS)
  361. @item @tab structure @code{jars}
  362. @item @code{mVar} @tab @code{make-jar}
  363. @item @code{mVarInit} @tab (no equivalent)
  364. @item @code{mPut} @tab @code{jar-put!}
  365. @item @code{mTake} @tab @code{jar-take}
  366. @item @code{mTakeEvt} @tab @code{jar-take-rv}
  367. @item @code{mGet} @tab (no equivalent)
  368. @item @code{mGetEvt} @tab (no equivalent)
  369. @item @code{mTakePoll} @tab (no equivalent)
  370. @item @code{mGetPoll} @tab (no equivalent)
  371. @item @code{mSwap} @tab (no equivalent)
  372. @item @code{mSwapEvt} @tab (no equivalent)
  373. @item @code{sameMVar} @tab @code{eq?} (R5RS)
  374. @item structure @code{Mailbox} @tab structure @code{rendezvous-async-channels}
  375. @item @code{mailbox} @tab @code{make-async-channel}
  376. @item @code{sameMailbox} @tab @code{eq?} (R5RS)
  377. @item @code{send} @tab @code{send-async}
  378. @item @code{recv} @tab @code{receive-async}
  379. @item @code{recvEvt} @tab @code{receive-async-rv}
  380. @item @code{recvPoll} @tab (no equivalent)
  381. @end multitable