[dmd-concurrency] draft 4

Kevin Bealer kevinbealer at gmail.com
Tue Jan 12 23:40:54 PST 2010


On Tue, Jan 12, 2010 at 5:16 PM, Andrei Alexandrescu <andrei at erdani.com>wrote:

> Sean Kelly wrote:
>
>> On Jan 12, 2010, at 12:45 AM, Andrei Alexandrescu wrote:
>>
>>  To be found at the usual location:
>>>
>>> http://erdani.com/d/fragment.preview.pdf
>>>
>>> I didn't add a lot of text this time around but I do have a full example
>>> of communicating threads. Skip to the last section for explanation. I paste
>>> the code below. I think it looks pretty darn cool. Sean, please let me know
>>> if it floats your boat.
>>>
>>> import std.concurrency, std.stdio;
>>>
>>> void main() {
>>>  auto low = 0, high = 1000;
>>>  auto tid = spawn(&fun);
>>>  foreach (i; low .. high) {
>>>     writeln("Main thread: ", message, i);
>>>     tid.send(thisTid, i);
>>>
>>
>> I haven't been able to come up with any difference in implementation for
>> using an interface vs. a free function that accepts an opaque type for
>> sending messages, so the choice seems largely a matter of how you want the
>> call to look.  I'll admit that I like "send(tid, thisTid, i)" since it
>> matches "receive(...)" but this is a small thing really.
>>
>
> You're echoing my thoughts as I was writing this. I'm undecided wrt
> tid.send(...) vs. send(tid, ...). I agree it is more symmetric with receive.
> Probably I'll use the free form. Other opinions?


I like the free form better.  Once you start using foo.method(...) you are
implying that foo is the one stop shop for message passing behavior (or at
least an important part of a balanced breakfast).  If I see
Logging::setLogLevel(...) in a program, I assume that all the invariants and
what not (related to system logging anyway) are encapsulated in Logging's
interface.  If the other pieces are free functions then that isn't the case
here.


>      enforce(receiveOnly!Tid() == tid);
>>>
>>
>> This could be a wrapper for the usual recvmsg call, so no big deal.
>>
>
> Right. Note that receiveOnly is very strict: if you send anything else than
> what's expected, it raises an exception. This makes mailbox crowding
> impossible.
>
>
>  What I'd like to do now that I haven't been able to because of a compiler
>> bug is allow a timeout and catchall receiver to be supplied to the full
>> recvmsg call:
>>
>> recvmsg( after(5, { writefln( "no message received!" ); },
>>                  any( (Variant v) { writefln( "got something: %s", v ); }
>> ) );
>>
>
> This is cute, perhaps a bit too cute. My objections are many but minor:
>
> * "recvmsg" is an awful name that evokes to me the name of a Cobol routine.
> It's very difficult to use in a conversation, and my accent doesn't help
> either :o). I think "receive" is a definite improvement.
>
> * Instead of after(...) as a clause, I'd rather have a receiveTimed (or
> recvmsgtmd if you wish) that takes a timeout value and returns true or
> false. I mean I'm not sure what moving the timeout code inside the call to
> recvms... I mean receive  would gain us.
>
> * The "any" wrapper is, I think, unnecessary. Dispatching on Variant will
> always catch everything because everything is packed in a Variant to start
> with.
>
> So I'd rewrite your example as:
>
> if (!receiveTimed(5000,
>
>        (Variant v) { writefln( "got something: %s", v ); }))
> {
>     writefln( "no message received!" );
>
> }
>
>  I guess the "any" wrapper could be dropped for the catchall routine and
>> some special casing could be done inside recvmsg:
>>
>> recvmsg( (Variant v) {...} );
>>
>
> Ah, there we go.
>
>
>  though I do kind of like that "any" (or whatever it would be called) is
>> obvious at a glance and greppable.
>>
>
> Well I think understanding that messages are packed as one Variant must be
> very basic knowledge. You accept Variant => you accept anything.
>
>
>   }
>>>  // Signal the other thread
>>>  tid.send(Tid(), 0);
>>>
>>
>> I've considered having the sender's Tid automatically embedded in every
>> message.  Seems like it's pretty much always wanted, though this would mean
>> not being able to use just any old delegate for receiving messages.  ie. if
>> you have a function already that accepts a Foo then would you want to use
>> that directly or would it be a bother to wrap it in something to throw away
>> the Tid?
>>
>
> Per Steve's point I think this has been settled.
>
>
>  Finally, I'd like for recvmsg to accept either a function returning void
>> for "accept any of this type" as well as functions returning a bool for "if
>> returns true, the passed value was a match, if false then not" to allow
>> dynamic pattern matching.  Seems like this should be easily possible with a
>> static if inside the recvmsg loop, but I haven't actually tried it yet.
>>
>
> Sounds great! I'll add that explanation later on.
>
>
>  }
>>>
>>> void fun() {
>>>  for (;;) {
>>>     auto msg = receiveOnly!(Tid, int)();
>>>     if (!msg[0]) return;
>>>
>>
>> Oh, so this format returns a Tuple for multiple arguments and the value
>> for a single argument?  The Tuple is gone by the time the user code is hit
>> with recvmsg so it would have to rewrap it for receiveOnly, but if that's
>> okay then this would work.  I guess the other option would be a completely
>> separate receiveOnly call instead of a wrapper, which could eliminate the
>> extra work.
>>
>
> Yah, exactly. As long as it's just an implementation matter, it could use a
> bit of a roundabout mechanism. I think it saves the user of a fair amount of
> manual unpacking.
>
> I'm very glad to see this much shared vision!
>
>
> Andrei
>
> _______________________________________________
> dmd-concurrency mailing list
> dmd-concurrency at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-concurrency
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/dmd-concurrency/attachments/20100113/5dab2013/attachment-0001.htm>


More information about the dmd-concurrency mailing list