Usage of Shared

Stanislav Blinov stanislav.blinov at gmail.com
Sat Feb 8 06:42:12 PST 2014


On Friday, 7 February 2014 at 19:58:21 UTC, Colden Cullen wrote:
> Hi all,
>
> I've been trying to learn more about how the shared qualifier 
> works, and so far I haven't been able to find much. I've read 
> the "Migrating to Shared" article, as well as the shared 
> section in "Attributes", but neither really give a good 
> explanation on the details of what should be shared and what 
> shouldn't. If anyone has any resources that they can share to 
> help me (and others in the future) understand how and when to 
> use shared it would be greatly appreciated.
>
> Thanks for the help!

I don't think you'll find many responses, mainly because 'shared' 
is not yet fully supported by the runtime or Phobos, so people 
don't use it all that much.

In a nutshell, anything that is to be accessed concurrently from 
different threads should be shared.

For example, here's an excerpt from one of my ongoing endeavours 
from the "Testing some singleton implementations" topic:

--8<--

static void test(shared ulong* counter)
{
     auto sw = StopWatch(AutoStart.yes);
     foreach (immutable dummy; 0 .. loopLength)
     {
         _thread_call_count += enforce(TestClass.get() !is null);
     }
     sw.stop();
     atomicOp!"+="(*counter, sw.peek.hnsecs);
}

shared ulong timer;
foreach (immutable i; 0 .. threadCount)
     spawn(&test, &timer);
thread_joinAll();
immutable avgTotal = 
atomicLoad!(MemoryOrder.acq)(timer).to!double/threadCount;

-->8--

Here, every thread measures how long its loop runs and then adds 
this time to a global timer. Naturally, the global timer is 
shared. But simply adding the qualifier is not enough. You also 
have to make concurrent access to your shared data safe. In this 
case, it's done using atomic operations from core.atomic.

Note that in this particular example, I pass the counter into 
threads as pointer. I would prefer passing it by ref, but 
currently std.concurrency.spawn does not propagate changes to ref 
arguments.

Normally, if you just want to pass data around between threads 
(primitive types, structs, any value type), where each thread 
will have its own copy of the data, it doesn't need to be shared. 
However, once you need to access the data concurrently, you have 
to make it shared and provide synchronization appropriately.

References (class instances, pointers) are only allowed to be 
visible by several threads if they are shared. Thus, if you want 
to share a class instance, you'll need to create a shared 
constructor, and make all the relevant methods shared as well 
(while still maintaining thread safety in the methods' 
implementations). There are a couple of examples of shared 
lock-free data structures in Anrei Alexandrescu's "The D 
Programming Language" book (that particular chapter is published 
for free: 
http://www.informit.com/articles/article.aspx?p=1609144).

There are still a lot of unresolved issues with shared (i.e. 
containers, existing runtime and Phobos types, destructors...), 
and the community is focused on other areas of the language, so 
for now you won't get much out of it. However, writing code is 
the best way of finding issues and inconsistencies. Given time, I 
hope the situation will improve.


More information about the Digitalmars-d-learn mailing list