Thread overview
Re: how to handle shared arrays?
Jun 21, 2012
Jonathan M Davis
Jun 22, 2012
maarten van damme
Jun 22, 2012
Jonathan M Davis
June 21, 2012
On Thursday, June 21, 2012 21:00:32 maarten van damme wrote:
> I want to have two threads. One parses some content ever half hour and
> the other continuously parses commands passed from the first thread.
> When the second thread finished something it should send the results
> back to the first thread who'll present it to the user.
> The messages the second thread needs to send back is under the form of
> an array of a struct.
> 
> Right now I'm trying something like this:
> shared (T[]) mods=cast(shared (T[]))modifications.dup;
> send(tid, mods);
> 
> This gives me a rather odd-looking errormessage:
> C:\D\dmd2\windows\bin\..\..\src\phobos\std\variant.d(528): Error: function
> core. stdc.string.memcpy (void* s1, const(void*) s2, uint n) is not
> callable using arg ument types (ubyte[20u]*,shared(T[])*,uint)
> C:\D\dmd2\windows\bin\..\..\src\phobos\std\variant.d(528): Error: cannot
> implici tly convert expression (& rhs) of type shared(T[])* to const(
> void*)
> 
> How should I handle arrays that I will need to send back to another thread?
> Excuse me for all those questions, I'm really having a hard time
> grasping the D threading model.

When you send reference types across threads via std.concurrency, they need to either be shared or immutable (which is implicitly shared).

If it's shared, it _could_ be on both threads, or it could be one thread casting it to shared, passing it across, and the other thread casting away shared (in which case, the original thread must _not_ keep a reference to that data). However, IIRC while shared is _supposed_ to work with send and receive, it doesn't right now.

If it's immutable, it _could_ be on both threads, but if it is, all of the references to it must be immutable (which isn't necessarily the case if you cast to immutable rather than iduping or constructing the object as immutable). If you're passing it across threads, then you either idup it to pass a copy across, or you cast it to immutable (std.exception.assumeUnique does this with the advantage of documenting that you're saying that you're assuming that that's the only reference to that data) and pass it across. If you cast to immutable and pass it across, you can then either keep it as immutable on the other side, or you can cast away immutable (but if you cast away immutable, then it _must_ have been constructed as mutable on the original thread, because casting away immutable on something that's actually immutable or it's going to result in undefined and buggy behavior).

- Jonathan M Davis
June 22, 2012
Well, maybe idup is a bit better then assumeuniqe.
I don't work anymore with that mutable array on the workerthread but
using idup is in all cases allowed and cannot cause subtle bugs like
me reusing a mutable array that I've casted to immutable and send over
to another thread.
It's a shame that shared doesn't (yet) work, It looks a bit "dirty" to
convert to immutable and back to mutable simply to pass it over to
another thread...
June 22, 2012
On Friday, June 22, 2012 11:09:13 maarten van damme wrote:
> It looks a bit "dirty" to
> convert to immutable and back to mutable simply to pass it over to
> another thread...

It is, but casting to shared and back again is pretty much the same thing. So, in most cases, you're going to end up doing  one or the other if you're trying to pass ownership across threads rather than sending an immutable duplicate across. It would be great if there were a way in the type system to model transfering ownership from one thread to another, but there isn't (if nothing else, because it's not easy to do), so you get to choose between transferring ownship using "dirty" casts and duplicating data to send it across. Certainly, if efficiency isn't an issue, iduping is safer, since it's @safe rather than @system.

- Jonathan M Davis