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