Message passing concurrency and shared state
Mike Rettig has left a somewhat snarky comment on a post detailing a deadlock issue that I run into:
Locking on shared state? I thought you were a proponent of message based concurrency. This post demonstrates exactly why concurrency combined with shared state is so hard.
Looking forward to your next thread race or deadlock,
The problem with message passing concurrency is that the underlying assumption here is that there isn’t any shared state. But in my situation, that is no a valid assumption.
Let us see if I can give a good example of what I mean. Let us assume that we have a message passing the exchange the following messages:
- Session Created { Session Id }
- Statement Executed { Session Id, Statement Text }
- Query Sessions And Statements { }
Furthermore, you are not going to be make use of something like a DB to manage the state (which would handle the sharing issue for you), you have to manage everything in memory.
I would be very interested in hearing how you can design such a system without having shared state and locking.
Comments
something which could have help would be using persistent lists (like in clojure) in .net.
so for ex. OnSessionChange the UI gets a snapshot of the current list without the message passing overhead
having that would have avoided the lock in the UI-thread.
but there will always be some situations where you just need a lock.
are there any implementations for immutable, persistent lists in .net around? would be a nice part time project ;-)
Note that this isn't a single list that you need to track
it is a list of lists, and the values in the list change as new data comes in
i don't get your point, you can have a peristent list which contains persistent lists itself.
I assumed that the UI just needs the latest data to display. The UI thread doesn't do any modifications. Modifcations occure when a new session was added or a new query was fired. These modification cause the UI to refresh.
=> Therefor do this Session.ToArray() inside the Session Thread
the thing i want to remove by using a persistent datastructure is the lock in the UI Thread: ...aquireLock() { Session.ToArray()} releaseLock()...
chirdo,
Build the model that can support this, then. I tried, and I couldn't figure out how to do this.
That is why I posted this.
Try having such a model and updating it in multiple threads.
STM (Software Transactional Memory) looks like a promising model to manage shared state without locks. There's even an implementation in F# : cs.hubfs.net/.../4565.aspx .
@chrido: There are implementations of immutable collections for C#: BclExtras ( http://code.msdn.microsoft.com/BclExtras ), functional-dotnet ( http://code.google.com/p/functional-dotnet/ ) and probably others.
STM doesn't work in C#, and in the end, it would have to rely on locks to make it work.
Immutable collections doesn't work, I have to be able to change any part of the data at will
STM does work in C# but awkwardly so (see comments on weblogs.asp.net/.../...sactional-memory-and-f.aspx ). Of course it uses locks in its implementation but the point is that they're abstracted away.
Anyway I don't think it's production-ready yet, but it is an interesting model worth investigating nevertheless.
Writing concurrent systems without shared state is similar to writing distributed services - think in terms of dto's and service interfaces. The interfaces should be coarse grained and fully encapsulate how the internal state is stored and represented. Tell don't ask. A well designed message based system will include very little if any request/reply (asking for data). Everything should be fire and forget.
Avoiding shared state takes discipline in java and c#, but it is worth the effort. It actually isn't difficult once the mindset changes from shared state to messaging. Writing immutable dto's by convention isn't difficult and once committed to messaging, the application can be nicely decomposed into autonomous services.
Locking on shared state is a dead end. It cripples design and is unmaintainable. The next generation of languages all have concurrency solutions that don't involve locking. Unless you move on to a new language, IMO the best solution is to adopt a little discipline and use messaging correctly by breaking the habits of old.
Mike Rettig
Retlang & Jetlang Developer
http://code.google.com/p/retlang/
http://code.google.com/p/jetlang/
Mike,
All very well and good, but you are avoiding talking about the actual problem shown in the post
Maybe I don't see the full picture but I can't find any message passing in that post commented by Mike Rettig...I can't see that the backend really just sends messages to the UI. If that would be the case code close to the UI can then analyze the messages and update relevant View Models accordingly.
I would like to have a look at retlang. Mike, do you have Erlang background?
That .NET 4.0 stuff which is often termed "LINQ to Events" could also be an interesting programming model for such a problem...once it's in existence, obviously.
Frank & Mike,
Leave the UI aside, given the three messages that I specified, how do you build a coherent model of what is actually happening on the other side?
The sessions and queries are rather low level. The granularity probably needs to be coarsened. In any case, I'll take a stab at the messaging interfaces.
In Retlang, a fiber per session or a single fiber for all sessions should be used to encapsulate the state of the session(s).
Rather than allowing multiple threads to access the sessions, Retlang channels allow threads to submit asynchronous requests to change state or query the sessions. In turn, the session fiber sends asynchronous updates in response to those requests or other state changing events.
The channels give you that coherent model for the actors in the system to communicate and exchange state changes. The retlang channels would look something like this:
class SessionChannels {
// published from the session fiber to all subscribers
// (ui, domain, or any other fiber) interested in the state change
IChannel <sessionsummary SessionUpdate = ...
IChannel <statementupdate StatementUpdate = ...
// Sent to the session fiber from ui, server, or any other thread
IChannel <executionrequest ExecutonRequest = ...
IChannel <sessionquery SessionRequest = ..
}
I don't know your application well, so I'm sure those channels are not even close to being correct. The key point is that the state is owned by a single fiber and the channels provide an asynchronous interface to change or query the state.
Mike,
The sessions & queries is what I have.
The messages are incoming from the profiled application.
I take them and turn then into a coherent model and then there is a different thread to manage that.
I like the notion of fibers, though, I'll look into it
The Axum Incubation project looks like an interesting take on message passing, shared state and consumer / producers.
msdn.microsoft.com/en-us/devlabs/dd795202.aspx
Comment preview