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