On Mon, May 19, 2008 at 1:45 PM, Martin Berger wrote: > Jon Harrop wrote: > > Similarly, avoiding threads removes concurrency bugs... >>> >> > I don't believe you have removed any concurrency bugs. I think you just >> pushed them around a bit. >> > > I couldn't agree more. If you 'avoid' concurrency by writing your own > 'sequential' event handling code, you have not removed the concurrency, > you just face it in a slightly different form, and you have to > program the event handling code yourself, rather than relying > on a tried and tested library, i.e. you have an additional > source of bugs, without removing the problems that are inherent > in concurrency (e.g. deadlocks, livelocks, fairness ...). There > are reasons why writing your own concurrency mechanisms might > be the way to go, but it's a highly non-trivial endeavor. Let's say that there are two kinds of concurrency bugs : consistency bugs and synchronization bugs. - Consistency bugs arise when two or more threads mutate the same datastructure concurrently, leading to inconsistent data. - Synchronization bugs occur when you have things like starvation (a queue with waiter never gets filled), unfairness (some code almost never gets a chance to run), deadlocking (ye olde deadlock), livelocking (threads spend time communicating back and forth without making progress), etc. Avoiding threads means to me that you're either using Lwt-style monadic threads, or an event-based framework (the two being similar). Avoiding threads almost eliminates consistency bugs. Code you write is, by default, atomic. Concurrency must be explicitly invoked, and generally shows in the types of functions using concurrency (one of the situations where monad creep seems to be a good thing.) If you take a data structure that was not intended for concurrency, then it will almost certainly be concurrency-safe unless it is some kind of structure that can store thunks and invoke them, and you store concurrency-producing thunks in them. Hence, using, say, Lwt, I can have tens of thousands of lightweight threads that happily mutate an unprotected, possibly complex datastructure implemented in a concurrency-agnostic module. For instance, I can and do use a global reference to a Map module and mutate it without any lock of any kind. Now let me classify synchronization bugs in two sorts : - Type A: Logical synchronization bugs due to algorithmic issues (livelocks, etc.) - Type B: Synchronization bugs due to consistency bug avoidance techniques, Short of a formal system where concurrency properties are statically proven, you probably can't avoid type A bugs, since it's a high-level correctness issue. Take for instance two mutually-recursive functions calling themselves using an inter-process mechanism. If they were supposed to terminate, it's a livelock, otherwise - if they are some kind of persistent client-server combination, they are running as usual. Yet they will be using the same primitives. So no one expects logical synchronization bugs to be statically detected. Type B bugs typically occur when you or someone else peppers code with locks/unlock pairs (or "synchronized" attributes, or "perform_under_lock" higher-order function...) and get a deadlock. While some type B bugs can be dynamically (and even statically) detected, or some lock/unlock pairs be removed by your JIT, others type B bugs will slip thru: even if you maintain some kind of dependency graph between locks, as you cannot model a synchronization effect conditioned on another lock if the unlocking goes thru a piece of unknown code. If you avoid threads, type A bugs become much less likely. Hence you won't need to wrap almost every shared datastructure with locks to prevent them, and hence you will avoid a lot of type B bugs. In short, with monadic threads, you can safely invoke non-concurrent code from concurrent code. (The inverse can be dangerous - but you usually don't do this anyway since you will end up optaining an 'a Lwt.t). This means that locking is almost never needed and hence your code is safer. Sequential, yes, but safer. -- Berke Durak