
On 28 March 2006 00:24, Ross Paterson wrote:
On Mon, Mar 27, 2006 at 09:36:28AM +0100, Simon Marlow wrote:
The portable interface could be Control.Concurrent.MVar, perhaps.
As Malcolm pointed out, using MVars requires some care, even if you were just aiming to be thread-safe.
I don't really understand the problem, maybe I'm missing something. I thought the idea would be that a thread-safe library would simply use MVar instead of IORef. So instead of this: do x <- readIORef r ... writeIORef r x' you would write do modifyMVar_ r $ \x -> ... return x' actually the second version is not only thread-safe, but exception-safe too. Malcolm's objections:
But Q2 explicitly raises the issue of whether a non-concurrent implementation must still follow a minimum API. That could be a reasonable requirement, if we fleshed out the detail a bit more. The specific suggestion of requiring MVars makes me a tiny bit worried though. After all, MVars capture the idea of synchronisation between threads, and I assume that since a non-concurrent implementation has only one thread, that thread will be trying to MVar-synchronise with something that does not exist, and hence be blocked for ever. I can imagine that there are situations where synchronisation is entirely safe and free of blocking, but how to specify when it would be unsafe?
There's no synchronisation, because we're not writing multi-threaded code here. Just code that doesn't have any race conditions on its mutable state when run in a multi-threaded setting. Maybe you could elaborate on what problems you envisage? Back to Ross:
How about STM (minus retry/orElse) and TVars as the portable interface? They're trivial for a single-threaded implementation, and provide a comfortable interface for everyone.
Now that's a rather good idea. It does raise the bar for the concurrent implementations, though, and STM is not nearly as mature and well-understood as MVars. There do exist implementations of STM in terms of MVars (at least two I know of). Cheers, Simon