haskellconcurrencytvar

Haskell: How does TVar work?


How does TVar work? From what I've read it attempts to run all transactions immediately upon receiving them, however, a transaction completing invalidates other currently running transactions, which must then restart. Is this how TVar works?

If this was the case, if there were transactions 1ms long transactions occurring every 100ms, would that mean that a transaction that takes 200ms to process would never complete?


Solution

  • As long as two transactions access distinct TVars, they can both be committed simultaneously without invalidating each other.

    Just to make it clear when a transaction is invalidated, let's consider the following scenario:

    1. Suppose that t :: TVar Int is initialized to 0 and is read via readTVar t at the beginning of a transaction A.
    2. Meanwhile, in another thread, transaction B is started in which a writeTVar t 1 is executed. Assume that B commits before A. The STM system will check whether there are any inconsistencies and conclude that it is safe for B to commit at this point, so now writeTVar t 1 becomes effective.
    3. This, however, causes transaction A to be invalidated since the old value 0 of t was read at the beginning of A. (If A was allowed to commit, we would get a violation of atomicity.)

    The original paper [1] on Haskell's STM system (see Sec 6.5) answers your question:

    "Starvation is possible. For example, a transaction that runs for a very long time may repeatedly conflict with shorter transactions. We think that starvation is unlikely to occur in practice, but we cannot tell without further experience."

    [1] Tim Harris, Simon Marlow, Simon Peyton Jones, and Maurice Herlihy. ACM Conference on Principles and Practice of Parallel Programming 2005 (PPoPP'05).