Thread overview
std.concurrency bug?
May 20, 2014
Charles Hixson
May 20, 2014
Ali Çehreli
May 21, 2014
Charles Hixson
May 21, 2014
Charles Hixson
May 21, 2014
Ali Çehreli
May 22, 2014
Charles Hixson
May 23, 2014
Sean Kelly
May 20, 2014
Is it a bug that an immutable struct cannot be sent to a thread?  (It compiles without problem if I make all elements mutable.)
May 20, 2014
On 05/20/2014 11:38 AM, Charles Hixson via Digitalmars-d-learn wrote:
> Is it a bug that an immutable struct cannot be sent to a thread?  (It compiles
> without problem if I make all elements mutable.)

Does the struct have any mutable indirection? Then it is illegal. Otherwise, can you demonstrate with minimal code please?

Ali

May 21, 2014
On Tuesday, May 20, 2014 11:42:48 AM Ali Çehreli via Digitalmars-d-learn wrote:
> On 05/20/2014 11:38 AM, Charles Hixson via Digitalmars-d-learn wrote:
> > Is it a bug that an immutable struct cannot be sent to a thread?  (It compiles without problem if I make all elements mutable.)
> 
> Does the struct have any mutable indirection? Then it is illegal. Otherwise, can you demonstrate with minimal code please?
> 
> Ali
Nope.  Here it is (with the immutable tags removed):
/**	This is the only message that one cell sends to another.	*/
struct Msg
{	/**	The cell id# of the sender of the message.	*/
	uint64_t	from;
	/**	The cell id# of the recipient of the message.	*/
	uint64_t	to;
	/**	The kind of action the message is impelling.	*/
	Act	act;
	/**	The tick on which the message was accepted for transmission.
	 * This is set by std.datetime.Clock.currStdTime()	*/
	long	tick;
	/**	Distance between cells.  Not currently well defined except in
	 * the case of two words, in which case it is the number of words of
	 * separation, where adjacent is 1.	*/
	float	dist;
	/**	Not currently well defined.	*/
	int	value;

	this	(uint64_t from, uint64_t to, Act act, float dist, int value)
	{	this.from	=	from;
		this.to		=	to;
		this.act		=	act;
		this.tick	=	Clock.currStdTime;
		this.dist	=	dist;
		this.value	=	value;
	}
}


May 21, 2014
On Tuesday, May 20, 2014 11:42:48 AM Ali Çehreli via Digitalmars-d-learn wrote:
> On 05/20/2014 11:38 AM, Charles Hixson via Digitalmars-d-learn wrote:
> > Is it a bug that an immutable struct cannot be sent to a thread?  (It compiles without problem if I make all elements mutable.)
> 
> Does the struct have any mutable indirection? Then it is illegal. Otherwise, can you demonstrate with minimal code please?
> 
> Ali
Nearly a minimal example.  If  "void	sendMsg (Msg m){...}" is removed there's
not compilation error.

import	std.array;
import	std.concurrency;
import	std.datetime;
import	std.format;
import	std.stdio;
import	std.stdint;
import	std.string;
import	std.variant;

enum	numCThreads	=	4;


class	UnexpectedMessage	:	Exception { this (string s) { super (s);
} }

enum	Act	{create, activate, deactivate, wait, read, reset, save, done}
string	toString(E)(E value) if (is(E == enum))
{	foreach (s; __traits(allMembers, E))
	{	if (value == mixin("E." ~ s) )	return	s;	}
	return	null;
}	//	string	toString (...  for enum

/**	This is the only message that one cell sends to another.	*/
struct Msg
{	/**	The cell id# of the sender of the message.	*/
	immutable	uint64_t	from;
	/**	The cell id# of the recipient of the message.	*/
	immutable	uint64_t	to;
	/**	The kind of action the message is impelling.	*/
	immutable	Act	act;
	/**	The tick on which the message was accepted for transmission.
	 * This is set by std.datetime.Clock.currStdTime()	*/
	immutable	long	tick;
	/**	Distance between cells.  Not currently well defined except in
	 * the case of two words, in which case it is the number of words of
	 * separation, where adjacent is 1.	*/
	immutable	float	dist;
	/**	Not currently well defined.	*/
	immutable	int	value;

	this	(uint64_t from, uint64_t to, Act act, float dist, int value)
	{	this.from	=	from;
		this.to		=	to;
		this.act		=	act;
		this.tick	=	Clock.currStdTime;
		this.dist	=	dist;
		this.value	=	value;
	}
}

void	cellThread(size_t ndx, shared(Tid)[] cThreads)
{	/**	Unprocessed message queue, indexed by cell id#.	*/
	Msg	msgs[uint64_t][];
	bool	done	=	false;

	//TODO	load the cells into the thread
	/**	Receive all messages in the mailbox.  Wait 2 ns for response.	*/
	while (!done && receiveTimeout (0.seconds,
			(Msg m)
				{	if	(m.to in msgs)
					{	msgs[m.to]	~=	m;	}
					else
					{	msgs[m.to]	=	[m];	}
				},
			(Act act)
				{	switch (act)
					{	case	Act.done:	//	end cell processing
							done	=	true;
							break;
						default:
							auto s	=	format (
								"Error in thread %s:  received message
Act.%s",
								ndx, act);
							writefln (s);
							throw	new	UnexpectedMessage(s);
					}	//	switch (act)
				}	//(Act act)

			) )
	{
	}	//	while (!done && receiveTimeout

	void	sendMsg (Msg m)
	{	assert (m.to > 0);
		assert (m.to < lastId);
		int	ndx	=	m.to % numCThreads;
		Tid	ct	=	cast(Tid)cThreads[ndx];
		ct.send(m);
	}
}	//	void	cellThread()


void	main()
{	auto	cellTids	=	new shared(Tid)[numCThreads];
	foreach	(id; 0 .. numCThreads)
	{	auto	cThread	=	spawn(&cellThread, id, cellTids);
		cellTids[id]	=	cast(shared(Tid))cThread;
	}
	foreach	(cThread; cellTids)
	{	Tid	ct	=	cast(Tid)cThread;
		ct.send(Act.done);
	}
}


May 21, 2014
On 05/20/2014 05:24 PM, Charles Hixson via Digitalmars-d-learn wrote:

> On Tuesday, May 20, 2014 11:42:48 AM Ali Çehreli via Digitalmars-d-learn
> wrote:
>> On 05/20/2014 11:38 AM, Charles Hixson via Digitalmars-d-learn wrote:
>>> Is it a bug that an immutable struct cannot be sent to a thread?  (It
>>> compiles without problem if I make all elements mutable.)

Further reduced:

import std.concurrency;

struct S
{
    immutable int i;
}

void foo()
{}

void main()
{
    auto f = spawn(&foo);

    auto s = S();
    f.send(s);
}

I think this is a known issue with immutable and Variant, which std.concurrency uses for unknown messages. This looks related:

  https://issues.dlang.org/show_bug.cgi?id=5538

Ali

May 22, 2014
On Wednesday, May 21, 2014 01:19:32 PM Ali Çehreli via Digitalmars-d-learn wrote:
> On 05/20/2014 05:24 PM, Charles Hixson via Digitalmars-d-learn wrote:
>  > On Tuesday, May 20, 2014 11:42:48 AM Ali Çehreli via Digitalmars-d-learn
>  >
>  > wrote:
>  >> On 05/20/2014 11:38 AM, Charles Hixson via Digitalmars-d-learn wrote:
>  >>> Is it a bug that an immutable struct cannot be sent to a thread?  (It
>  >>> compiles without problem if I make all elements mutable.)
> 
> Further reduced:
> 
> import std.concurrency;
> 
> struct S
> {
>      immutable int i;
> }
> 
> void foo()
> {}
> 
> void main()
> {
>      auto f = spawn(&foo);
> 
>      auto s = S();
>      f.send(s);
> }
> 
> I think this is a known issue with immutable and Variant, which std.concurrency uses for unknown messages. This looks related:
> 
>    https://issues.dlang.org/show_bug.cgi?id=5538
> 
> Ali
Thanks.  Fortunately, I don't really need for messages to be immutable, I just thought it would be safer (as in avoiding the possibility of making a mistake).  They're stucts, and I never pass a pointer, just the struct.  Being immutable would allow me to guarantee that certain logic errors couldn't be committed is all.

May 23, 2014
On Wednesday, 21 May 2014 at 20:19:32 UTC, Ali Çehreli wrote:
>
> I think this is a known issue with immutable and Variant, which std.concurrency uses for unknown messages. This looks related:
>
>   https://issues.dlang.org/show_bug.cgi?id=5538

std.concurrency actually uses Variant as the transport mechanism for all messages, and this is most likely the cause of your problem.  If this is just to make a class pass type checking for transport, casting to shared is probably a better bet.  The real solution is to make std.concurrency effectively allow uniquely referenced classes to be transferred, but that's a bit farther out.