[Haskell] Re: [Haskell-cafe] SimonPJ and Tim Harris explain STM - video

Chris Kuklewicz haskell at list.mightyreason.com
Thu Nov 30 06:12:51 EST 2006


Eureka,

I claim to have written an implementation which agrees with all the semantics
that Simon Peyton-Jones wants for onCommit/onRetry/retryWith.  See below:

Simon Peyton-Jones wrote:
> | In many useful cases, such as the getLine example, the Y action will have its
> | own atomic {} block.  In which case the semantics of when it is allowed to
> | re-attempt X are what is important.  If you require (Y) to complete before
> | re-attempting (X) then you get an infinite regression where every (atomic block)
> | fails with (retryWith (next atomic block)), and nothing is ever re-attempted.
> | This is why "retryWith Y" meaning rollback X and do "Y >> atomic X" is the wrong
> | implementation.
> 
> I don't agree. I think it's quite reasonable. Not many atomic blocks will
> finish with retryWith. Of course there is a possibility of an infinite loop, but
> we already have that: f x = f x. Of course, Y can always choose to do a forkIO,
> but it shouldn't hav to.
> 
> For me the only difficulty is the implementation. We'd like to block X on the
> TVars it read (as usual), *unless* executing Y wrote to any of them. That
> requires a bit more cleverness in the commit code, but not a great deal I think.
> 
> Simon

It is the Helper Thread code version on the wiki at
http://haskell.org/haskellwiki/New_monads/MonadAdvSTM#Helper_Thread_Code

Quick explanation of the code for runAdvSTM (usually called with atomicAdv):

When the action X in (atomicAdv X) ends with (retryWith Y) the job Y is put into
an MVar.  Then a retry causes the orElse in wrappedAction to perform
check'retry.  This sees the job Y and then
 *) if this is the first retry job: creates and cache a channel and spawn the
helper thread
 *) push the retry job Y into the channel
 *) call retry to cause action X to cause the current GHC runtime to block on
whatever STM-variables it used

The wrappedAction commits if and only if the action X commits.  In which case
the commit action stored in the TVar is read and performed.  Then a check is
performed to see if the helper thread was spawned, and if so tell the helper
thread to quit and block until the helper thread is done.

Note that the action X can be re-attempted by the runtime before the retry job Y
is run or before it has finished running.  But this will only happen in the
usual cases where there was an STM update, instead of the possible busy wait in
the Single Thread code example on the wiki page.

Does this meet your specifications, Simon?

-- 
Chris


More information about the Haskell-Cafe mailing list