Saturday, January 19, 2013

Concurrency design with D

During my development with CivBot (an IRC bot written in D) I have come across some things which make me go wow; One of these is threading.
This may seem like well just use mutexs but how can you really use it efficiently is what I am trying to come to grips with.
I'm looking at two types of concurrency in D, mutexs and message passing.


Mutexs is the old method of locking memory for reading and writing. It works but you have conditions where you could have dependencies locked and all sorts; Which could lead to locking up the whole application.
This does lead to non independent threads which may or may not be what you want.

The other is message passing. Basically each thread is meant to be isolated and all data transmitted between threads is immutable. That's great but that requires you to request data and then receive it and wait for it. You can't really do that when your then going to pass it into a scripting engine on request of said engine.

Here's an issue I faced. How do I control a thread from another? My solution was to implement a manager for each thread type there was. Remember the thread will use message passing.
I liked it, and still do; but one problem. How do you get state from another thread?
I choose to put in the main thread which held another manager which had the manager for the thread as __gshared. That enabled not worrying about marking the other managers as shared and all sorts; while taking it out of TLS (thread local storage). Then inside the manager for the thread added the state information and got the thread to send said state to it when it updated.
I believe this part was a complete mistake now.

Yes a thread should be completely isolated. Its state though should be semi so. So how do we do it?
Well in the same file as the manager for the thread we could store as an array __gshared StateStruct[]states; and have the manager for the thread automatically add AND nullify on destruction the state. Okay but how do we update the actual state? As before message passing. Pass to the main thread the state for said thread with an id which was passed to the thread on creation.
Wait but how do we solve the whole condition for if we are writing and another thread goes and try to read it? Synchronization using a RWMutex. A RWMutex by default will allow for many readers for a variable but few writers.
Now getting the data out of the state for it. You have two choices returning the struct as a value or as a pointer (lets ignore returning each item of the struct as you have to complete this anyway in the process). Well the struct data is already known to be immutable / shared because it was able to get into the array from another thread using message passing. So by value is quite safe until another thread decides it wants to modify it. Same issue with a pointer; but by pointer the information could update and the receiver will get it instantly without extra function calls.
An option is to copy the struct and return it. If it gets modified who cares doesn't matter. Another but a much more preferable one is to mark the struct type as immutable. Does require on initiation to have all values set though.
This I believe to be the best option for saving state information about a thread (__gshared immutable(StateStruct)[]). When ever you access any information in it you will need to synchronize with the RWMutex but this is acceptable. It will add in the overhead of it; but if you design it to get the state limited to  every tick and copy it every time it will be considerably less then every single time its needed. However every tick of a thread should complete the minimal amount of actions possible; But I won't get into that.

The last thing I really want to say on this is that managers for threads really shouldn't be keeping too much information. It really should be you can make x and y happen by calling these methods. Managers them selves should be create able in any thread given the thread id that it managers. Given this and how the state information is not kept inside the manager but outside of TLS and any instance of a class it could very well be.

I have tried to keep the message passing rules around keeping threads isolated in this design as much as possible. But I do feel it needed to be broken slightly to allow for more easily access of information from other threads. Please do note though a state information of a thread does not include things like classes. It is read only data like what is the users name?

Or we could just send to each thread that could need it each other states which is a LOT easier.

I hope this interests somebody.

No comments:

Post a Comment