February 23, 2016
My goal with the code below is to eventually have my main communicate with Foo and Bar classes listening for packets on a different address/port, each in a separate thread. They would then communicate with Foobaz and Barbaz threads respectively to do other work. In trying to get just Foo working though, I'm getting this error:

Error: template std.concurrency.spawn cannot deduce function from argument types !()(void delegate(Tid ownerTid), Tid), candidates are:
D:\D\dmd2\windows\bin\..\..\src\phobos\std\concurrency.d(466):        std.concurrency.spawn(F, T...)(F fn, T args) if (isSpawnable!(F, T))

The code works fine if I call daemon as a normal function, but it holds up the main thread.

Is there anything I'm doing wrong here? I'm not accessing anything outside this class from inside, and the most I would be doing from outside is accessing the Tid in order to send packets from my main.

class Foo
{
	private string address = "127.0.0.1";
	private ushort port = 55555;
	private ubyte[256] buffer;
	private TcpSocket mysock;
	Tid listenerd;
	
	this()
	{
		listenerd = spawn(&daemon, thisTid);
	}
	
	void setup()
	{
		mysock = new TcpSocket();
		mysock.blocking = true;
		try
		{
			mysock.connect(new InternetAddress(address, port));
		}
		catch (SocketOSException e)
		{
		}
	}
	
	void initialise()
	{
		// send init packet
	}
	
	void closeConnection()
	{
		// send close packet
	}
	
	void packetHandler()
	{
		// do something with buffer
	}
	
	void daemon(Tid ownerTid)
	{
		setup();
		initialise();
		int rxSize = -1;
		while (true)
		{
			rxSize = mysock.receive(buffer);
			if (rxSize == 0)
			{
				break;
			}
			packetHandler();
		}
		closeConnection();
	}
}
February 23, 2016
On 02/23/2016 07:31 AM, Josh wrote:
> My goal with the code below is to eventually have my main communicate
> with Foo and Bar classes listening for packets on a different
> address/port, each in a separate thread.

The main issue is that in D all data is thread-local by-default. main() cannot create objects and then implicitly give access to those objects from other threads.

> the most I would be doing from outside is accessing the Tid in order
> to send packets from my main.

Even that's not needed because spawn() returns the Tid. And you don't need to pass ownerTid, it is already available to child threads.

Options:

a) spawn() a thread by passing necessary data for it to create a Foo. (Preferred.)

b) In case main() needs to have access to the objects, construct objects as shared(Foo) and pass references to threads.

Here is the code with option a:

import std.socket;
import std.concurrency;

void daemon()
{
    auto f = new Foo();

    f.setup();
    f.initialise();
    long rxSize = -1;
    while (true)
    {
        rxSize = f.mysock.receive(f.buffer);
        if (rxSize == 0)
        {
            break;
        }
        f.packetHandler();
    }
    f.closeConnection();
}

class Foo
{
    private string address = "127.0.0.1";
    private ushort port = 55555;
    private ubyte[256] buffer;
    private TcpSocket mysock;
    Tid listenerd;

    void setup()
    {
        mysock = new TcpSocket();
        mysock.blocking = true;
        try
        {
            mysock.connect(new InternetAddress(address, port));
        }
        catch (SocketOSException e)
        {
        }
    }

    void initialise()
    {
        // send init packet
    }

    void closeConnection()
    {
        // send close packet
    }

    void packetHandler()
    {
        // do something with buffer
    }

}

void main() {
    auto listenerd = spawn(&daemon);
}

Ali