std.concurrency and immutable

Shammah Chancellor anonymous at coward.com
Tue Nov 26 03:57:53 PST 2013


On 2013-11-25 20:55:15 +0000, Antoche said:

> On Monday, 25 November 2013 at 11:48:06 UTC, Shammah Chancellor wrote:
>> On 2013-11-25 06:03:27 +0000, Antoche said:
>> 
>>> The following code compiles but doesn't work as expected:
>>> 
>>> import std.stdio;
>>> import std.concurrency;
>>> 
>>> class A
>>> {
>>> this() immutable {}
>>> }
>>> 
>>> void main()
>>> {
>>> auto tid = spawn( &fooBar, thisTid );
>>> while(true)
>>> {
>>> receive(
>>> (Variant any) {
>>> writeln( "Received a variant" );
>>> writeln( "Received ", any );
>>> }
>>> );
>>> }
>>> }
>>> 
>>> void fooBar( Tid masterTid )
>>> {
>>> scope(failure) writeln( "fooBar failed" );
>>> scope(success) writeln( "fooBar succeeded" );
>>> scope(exit) writeln( "fooBar exiting" );
>>> try
>>> {
>>> immutable A b = new immutable A();
>>> masterTid.send( 42 ); // This works
>>> masterTid.send( b );  // This doesn't
>>> }
>>> catch( Exception e )
>>> {
>>> writeln( "Exception received" );
>>> }
>>> }
>>> 
>>> 
>>> I see this in the console:
>>> 
>>> fooBar exiting
>>> fooBar failed
>>> Received a variant
>>> Received 42
>>> 
>>> (then it just hangs)
>>> 
>>> I'm especially puzzled by:
>>> * Sending an int as a message works but not an immutable object.
>>> Wasn't this  (safely sharing objects across threads) one of the
>>> basic use cases for the immutable type qualifier?
>>> * scope(failure) failed but my exception handler didn't catch
>>> anything. How is this possible? What could cause that?
>>> Assertions/abort?
>>> 
>>> There seemed to be a 3-year-old ticket on this issue
>>> (http://d.puremagic.com/issues/show_bug.cgi?id=5538) with very
>>> little activity, which is a bit surprising given how much
>>> emphasis is given to this feature (the D homepage mentions "D
>>> offers an innovative approach to concurrency, featuring true
>>> immutable data, message passing, no sharing by default, and
>>> controlled mutable sharing across threads", and TDPL devotes a
>>> whole chapter on it). This thread
>>> (http://forum.dlang.org/thread/kgk8hc$12fa$1@digitalmars.com)
>>> also says std.concurrency is "very buggy".
>>> 
>>> If I can't use std.concurrency, is there any other safe
>>> alternative for multithreaded programming with D?
>>> 
>>> Thanks,
>>> A.
>> 
>> 
>> There is a bug with the internals of send/receive.   It has to be able 
>> to copy the reference to a another place while sending --  and it seems 
>> it can't do that because it's immutable.     I don't think many people 
>> are using it.    I personally did not realize the bug was from 2011.  I 
>> think DMD has been fixed enough to make a patch to phobos now.  I'm 
>> going to ping this bug report.
>> 
>> However,  even CONSTRUCTING immutable objects right now is very 
>> difficult.   It's arguably "correct" but, seems impossible to actually 
>> be able to make something of use without many many idups.  It's kind of 
>> in the same boat as shared.
>> 
>> What I am currently doing, is casting to shared, and then back.
>> I tried making my classes shared, and also immutable as you have.   
>> Nothing else seems to work:
>> 
>>> class A
>>> {
>>> this() {}
>>> }
>>> 
>>> void main()
>>> {
>>> auto tid = spawn( &fooBar, thisTid );
>>> while(true)
>>> {
>>> receive(
>> 		   (shared A _m)
>> 	     	   {
>> 			auto m = cast(A)_m;
>> 			//Do stuff.
>> 		   },
>>> (Variant any) {
>>> writeln( "Received a variant" );
>>> writeln( "Received ", any );
>>> }
>>> );
>>> }
>>> }
>>> 
>>> void fooBar( Tid masterTid )
>>> {
>>> scope(failure) writeln( "fooBar failed" );
>>> scope(success) writeln( "fooBar succeeded" );
>>> scope(exit) writeln( "fooBar exiting" );
>>> try
>>> {
>>> immutable A b = new A();
>>> masterTid.send( 42 ); // This works
>>> masterTid.send( cast(shared) b );  // Should work
>>> }
>>> catch( Exception e )
>>> {
>>> writeln( "Exception received" );
>>> }
>>> }
>> 
>> -Shammah
> 
> Thanks for the suggestion. My problem with casting is that it results 
> in undefined behaviour, so I have no guarantee whatsoever what the 
> program is actually going to do. I could simply not use immutable at 
> all, and use shared instead, but then I might as well stick to C++ and 
> volatile. The whole point of using D was trying to write safer code 
> with equivalent performance.
> 
> I see std.parallelism seems to offer some features that might 
> compensate for the broken std.concurrency. Is it working better or is 
> it as broken as std.concurrency? Is there any other way to write safe 
> multithreaded programs?
> 
> Finally, can anyone explained why the scope(failure) is reached? 
> Looking at the stacktrace in gdb at this point gives me no indication 
> of what's happening.


Try wrapping it in a Try/catch and see.    Sending non-value types 
right now seems to be a bit frustrating.   Unless you *need* 
polymorphism for your messages I would suggest sending immutable struct 
references or something.   Or you can also use the idea I suggested and 
cast(const) to ensure you are not messing with the data again 
afterwards.    I am going to ping this issue very heavily though, and 
possibly start working on std.concurrency myself.   The current state 
of the library is unacceptable.

-Shammah



More information about the Digitalmars-d-learn mailing list