View mode: basic / threaded / horizontal-split · Log in · Help
April 14, 2012
"shared" status
What is the status of "shared" types ?

I try it with gdmd v4.6.3
And I not get any warring/error when I do anything over a shared variable 
without using atomicOp. It's normal ?

shared ushort ram[ram_size];
....
....
ram[i] = cast(ushort) (bytes[0] | bytes[1] << 8);

-- 
I'm afraid that I have a blog: http://zardoz.es
April 15, 2012
Re: "shared" status
On Saturday, 14 April 2012 at 10:48:16 UTC, Luis Panadero 
Guardeño wrote:
> What is the status of "shared" types ?
>
> I try it with gdmd v4.6.3
> And I not get any warring/error when I do anything over a 
> shared variable
> without using atomicOp. It's normal ?
>
> shared ushort ram[ram_size];
> ....
> ....
> ram[i] = cast(ushort) (bytes[0] | bytes[1] << 8);

Shared is at the moment (in my opinion anyways) not useable. Very 
little in Phobos is shared friendly. Most benefits of shared 
aren't implemented yet. I personally avoid it.
April 16, 2012
Re: "shared" status
El Sun, 15 Apr 2012 23:05:55 +0200, Kapps escribió:

> On Saturday, 14 April 2012 at 10:48:16 UTC, Luis Panadero Guardeño
> wrote:
>> What is the status of "shared" types ?
>>
>> I try it with gdmd v4.6.3
>> And I not get any warring/error when I do anything over a shared
>> variable
>> without using atomicOp. It's normal ?
>>
>> shared ushort ram[ram_size];
>> ....
>> ....
>> ram[i] = cast(ushort) (bytes[0] | bytes[1] << 8);
> 
> Shared is at the moment (in my opinion anyways) not useable. Very little
> in Phobos is shared friendly. Most benefits of shared aren't implemented
> yet. I personally avoid it.

So, if I need to share a array of 0x10000 elements between 3 or more 
threads, how should do it ?
April 17, 2012
Re: "shared" status
On 04/16/2012 03:57 AM, Zardoz wrote:

> So, if I need to share a array of 0x10000 elements between 3 or more
> threads, how should do it ?

1) The following program starts four threads to fill different parts of 
a shared array:

import std.stdio;
import std.concurrency;
import core.thread;

void numberFiller(shared(int)[] area, int fillValue)
{
    foreach (ref number; area) {
        number = fillValue;
    }
}

void main()
{
    enum totalNumbers = 0x10;
    auto numbers = new shared(int)[totalNumbers];

    enum totalThreads = 4;
    enum numbersPerThread = totalNumbers / totalThreads;

    foreach (i; 0 .. totalThreads) {
        immutable start = i * numbersPerThread;
        immutable fillValue = i;

        spawn(&numberFiller,
              numbers[start .. start + numbersPerThread],
              cast(int)fillValue);
    }

    thread_joinAll();

    writeln(numbers);
}

The output:

[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]


2) The program above is being careful to limit the threads to different 
parts of the array. In other cases lock-based multi-threading can be 
used. The following program allows four thread append to a single array 
as they get a hold of the slice:

import std.stdio;
import std.concurrency;
import core.thread;
import std.random;

class Job
{
    int[] * slice;
    size_t count;

    this(ref int[] slice, size_t count)
    {
        this.slice = &slice;
        this.count = count;
    }
}

void numberAppender(shared(Job) job, int appendValue)
{
    foreach (i; 0 .. job.count) {
        synchronized (job) {
            *job.slice ~= appendValue;
        }

        Thread.sleep(dur!"msecs"(uniform(1,100)));
    }
}

void main()
{
    enum totalNumbers = 0x10;
    int[] numbers;

    enum totalThreads = 4;
    enum numbersPerThread = totalNumbers / totalThreads;

    auto job = new shared(Job)(numbers, numbersPerThread);

    foreach (i; 0 .. totalThreads) {
        int appendValue = i;

        spawn(&numberAppender, job, appendValue);
    }

    thread_joinAll();

    writeln(numbers);
}

The output should be similar to this:

[0, 1, 3, 2, 1, 1, 2, 0, 3, 1, 3, 0, 2, 3, 0, 2]

(Note: I wish there were 'ref' variables in D. That's why Job.slice 
above had to be a pointer.)


3) Better than the two approaches above may be to use message passing 
and have the threads produce separate results to be either combined 
later or simply used separately:

import std.stdio;
import std.concurrency;

void arrayMaker(Tid owner, int count, int value)
{
    immutable(int)[] result;

    foreach (i; 0 .. count) {
        result ~= value;
    }

    owner.send(result);
}

void main()
{
    enum totalNumbers = 0x10;
    enum totalThreads = 4;
    enum numbersPerThread = totalNumbers / totalThreads;

    foreach (i; 0 .. totalThreads) {
        int value = i;
        spawn(&arrayMaker, thisTid, numbersPerThread, value);
    }

    immutable(int[])[] results;

    foreach (i; 0 .. totalThreads) {
        auto result = receiveOnly!(immutable(int)[])();
        results ~= result;
    }

    writeln(results);
}

The output should be similar to this:

[[0, 0, 0, 0], [1, 1, 1, 1], [3, 3, 3, 3], [2, 2, 2, 2]]

(Note: I could not pass the results as shared int slices so I went back 
to immutable.)

Ali
April 17, 2012
Re: "shared" status
Thanks! It's very useful.

Ali Çehreli wrote:

> synchronized (job) {
> *job.slice ~= appendValue;
> }
So shared, at least share data across threads. And using synchronized( ) 
I could do lock-based access to shared data.
April 17, 2012
Re: "shared" status
On 04/17/2012 06:05 AM, Luis wrote:
> Thanks! It's very useful.
>
> Ali Çehreli wrote:
>
>> synchronized (job) {
>> *job.slice ~= appendValue;
>> }
> So shared, at least share data across threads. And using synchronized( )
> I could do lock-based access to shared data.
>

Yes. I've used the same Job object there but any class is a lock. (This 
has been a new concept for me. The "lock part" of the object is called 
the monitor.)

Ali
April 17, 2012
Re: "shared" status
On Saturday, 14 April 2012 at 10:48:16 UTC, Luis Panadero 
Guardeño wrote:
> What is the status of "shared" types ?
>
> I try it with gdmd v4.6.3
> And I not get any warring/error when I do anything over a 
> shared variable
> without using atomicOp. It's normal ?
>
> shared ushort ram[ram_size];
> ....
> ....
> ram[i] = cast(ushort) (bytes[0] | bytes[1] << 8);

Shared is crucial for concurrency/parallelism since the switch to 
the thread local storage as default storage.

Immutable values are IMPLICITLY SHARED while for your mutable 
data you have to explicitly use "shared" keyword.

This basically means that SHARED data are used everywhere in D 
applications nowadays.
Top | Discussion index | About this forum | D home