www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Allow object local MessageBox's in concurreny

reply "monarch_dodra" <monarchdodra gmail.com> writes:
I've been playing around with concurrency lately, and I brought 
up a limitation (which I feel is very strong): Basically, each 
MessageBox are thread-global objects.

Because of this, it is not possible (or at least, very difficult) 
to create *objects* that own other threads and communicate with 
said threads, all from the same master thread.

It turns out the limitation is mostly artificial. I added a 
couple of lines to concurrency, and I was able to *very* easily 
deploy code such as:

//--------
import std.stdio;
import std.concurrency;
import core.thread;
import core.time;

void job(Tid ownerTid, string s, Duration duration)
{
     Thread.sleep(duration);
     ownerTid.send("Job " ~ s ~ " has finished.");
}

struct Manager
{
     string name;
     Tid myTid;
     this(string name, Duration duration)
     {
         this.name = name;
         myTid = generateMessageBox(); //New in concurrency
         spawn(&job, myTid, name, duration);
     }
     void get()
     {
         myTid.receive( //Specific member function to Tid
             (string s){writefln("Manager %s say: %s", name, s);}
         );
     }
}

void main()
{
     auto a = Manager("a", seconds(5));
     auto b = Manager("b", seconds(1));
     auto c = Manager("c", seconds(3));
     Thread.sleep(seconds(10));
     a.get();
     b.get();
     c.get();
}
//--------
Manager a say: Job a has finished.
Manager b say: Job b has finished.
Manager c say: Job c has finished.
//--------

As you can see, my main has created 3 Managers, all of which 
spawned their own thread. Each manager can easily speak to its 
job, via its own private MessageBox, with no risk of collateral 
noise.

Most importantly, deploying this code was *bafflinggly* easy and 
straight forward. Furthermore, it reduces to *nothing* end user 
message management.

In particular, imagine if "Manager" was instead:

struct AssyncFileCopier
{
     this(string origin, string target);
     bool areYouDoneYet();
}

Again, implementation would be VERY straight forward.

Without such local MessageBoxes, I don't know how you'd tackle 
the problem.

One thing is for sure, I don't think it would be very pretty...

--------

The question is: I'd like to put a bit more work into this, flesh 
it out, maybe write a DIP, and submit to phobos for inclusion.

Does anybody have any preliminary feedback, objections, remarks?
Feb 12 2013
parent reply FG <home fgda.pl> writes:
On 2013-02-12 14:47, monarch_dodra wrote:
 Does anybody have any preliminary feedback, objections, remarks?
You will encounter a possible problem on main thread termination. Normally it's done automatically in static ~this(): a linkDead message is sent to all spawned threads listed in "links" and then close() is called on the mbox. Those linkDead messages have thisTid as sender and that's a problem, because with custom mailbox thisTid != ownerTid, so the child won't treat that message as OwnerTerminated. It's caused by "links" being global and populated by spawn(). And if you make your own spawn, that doesn't touch links, the child won't be informed about parent's sudden death. How do you work around that?
Feb 12 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 12 February 2013 at 15:26:18 UTC, FG wrote:
 On 2013-02-12 14:47, monarch_dodra wrote:
 Does anybody have any preliminary feedback, objections, 
 remarks?
You will encounter a possible problem on main thread termination. Normally it's done automatically in static ~this(): a linkDead message is sent to all spawned threads listed in "links" and then close() is called on the mbox. Those linkDead messages have thisTid as sender and that's a problem, because with custom mailbox thisTid != ownerTid, so the child won't treat that message as OwnerTerminated. It's caused by "links" being global and populated by spawn(). And if you make your own spawn, that doesn't touch links, the child won't be informed about parent's sudden death. How do you work around that?
That's a good point. For starters, I'd call "myTid.spawn(...)" so as to set the correct "owner" for the spwaned thread. This is especially relevant what with the new global "ownerTid" that should get introduced in 2.062 The real question though (IMO) is rather: Why isn't "links" a member field of the MessageBox itself? By placing it inside MessageBox, it changes *nothing* for "static ~this()". As for user generated MessageBoxes, the message will be sent when the MessageBox itself is finalized. The only problem with this approach is that there might be a delay between when the last reference to the MessageBox is destroyed, and the finalizer actually kicks in. Not entirely sure this is a huge problem though, since we *are* dealing with threads after all. Also, just the same way a File can be closed either explicitly or implicitly, we can give Tid a "die" member to explicitly notify an incoming death. I'll put more thought into it anyways.
Feb 12 2013