Combining Unique type with concurrency module

Alex via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Mon Sep 14 00:07:35 PDT 2015


On Monday, 14 September 2015 at 00:11:07 UTC, Ali Çehreli wrote:
> On 09/13/2015 09:09 AM, Alex wrote:
> > I'm new to this forum so, please excuse me in advance for
> > asking silly questions.
>
> Before somebody else says it: There are no silly questions. :)
>
> > struct std.typecons.Unique!(S).Unique is not copyable because
> it is
> > annotated with @disable
>
> I have made the code compile and work (without any thread 
> synchronization at all). See the comments with [Ali] 
> annotations:
>
> import std.stdio;
> import std.concurrency;
> import std.typecons;
>
> void spawnedFunc2(Tid ownerTid)
> {
>     /* [Ali] Aside: ownerTid is already and automatically
>      * available. You don't need to pass it in explicitly. */
>
>     receive(
>         /* [Ali] The compilation error comes from Variant, which
>          * happens to be the catch all type for concurrency
>          * messages. Unfortunately, there are issues with that
>          * type.
>          *
>          * Although implemented as a pointer, according to
>          * Variant, a 'ref' is not a pointer. (I am not sure
>          * whether this one is a Variant issue or a language
>          * issue.)
>          *
>          * Changing the message to a pointer to a shared
>          * object: */
>         (shared(Unique!S) * urShared)
>         {
>             /* [Ali] Because the expression ur.i does not work 
> on
>              * a shared object, we will hack it to unshared
>              * first. */
>             auto ur = cast(Unique!S*)urShared;
>             writeln("Recieved the number ", ur.i);
>         }
>     );
>     send(ownerTid, true);
> }
>
> static struct S
> {
>     int i;
>     this(int i){this.i = i;}
> }
>
> Unique!S produce()
> {
>     // Construct a unique instance of S on the heap
>     Unique!S ut = new S(5);
>     // Implicit transfer of ownership
>     return ut;
> }
>
> void main()
> {
>     Unique!S u1;
>     u1 = produce();
>     auto childTid2 = spawn(&spawnedFunc2, thisTid);
>
>     /* [Ali] Cast it to shared so that it passes to the other
>      * side. Unfortunately, there is no guarantee that this
>      * object is not used by more than one thread. */
>     send(childTid2, cast(shared(Unique!S*))&u1);
>
>     /* [Ali] We must wait to ensure that u1 is not destroyed
>      * before all workers have finished their tasks. */
>     import core.thread;
>     thread_joinAll();
>
>     writeln("Successfully printed number.");
> }
>
> Note that thread synchronization is still the programmer's 
> responsibility.
>
> > I'm aware of the fact, that my u1 struct can't be copied, but
> I don't
> > intend to do so.
>
> Correct.
>
> > As in the docu stated, I want to lend the struct to the
> > other thread (by using ref), being sure, that any other
> thread can't
> > access the struct during it is processed by the first one.
>
> There is a misconception. Unique guarantees that the object 
> will not be copied. It does not provide any guarantee that only 
> one thread will access the object. It is possible to write a 
> type that acquires a lock during certain operations but Unique 
> isn't that type.
>
> > Is such a thing possible?
> > Thanks in advance.
> > Alex
>
> Ali

Thanks for answering!
Do you have a hint how to create such a type? The needed 
operation is "onPassingTo" another thread. So the idea is to 
create a resource, which is not really shared (a question of 
definition, I think), as it should be accessible only from one 
thread at a time.
But there is a "main" thread, from which the resource can be lent 
to "worker" threads and there are "worker" threads, where only 
one worker can have the resource at a given time.

On my own the next possibility I would try is something with 
RefCounting and checking, how many references there exist. 
Deciding on this number allow or disallow accessing the reference 
again.

By the way, synchronizing by hand is ok. Don't know how important 
that is, but the idea is, that synchronization appears very rare, 
as the lending process acquires and releases resources 
automatically and the next thread can acquire the resource after 
a release, the synchronization should not be expected 
systematically but only at some strange time points... I can't 
even give an example of such times now... maybe only at the end 
of the program, to let all workers end their existence.


More information about the Digitalmars-d-learn mailing list