Skip to content

CPU 8. Shared Memory

Phillip Allen Lane edited this page Nov 27, 2023 · 1 revision

It is often helpful to create shared memory within a parallel region. The DotMP Shared Memory API helps with this.

Shared Scalars

To create a shared scalar, you can use the shared memory factory. Shared memory implements IDisposable, so optimally it should be used within a using region. If not, you need to call Dispose() to free the memory when you're done.

DotMP.Parallel.ParallelRegion(() =>
{
    using (var sharedScalar = DotMP.Shared.Create("sharedScalar", 0))
    {
        // use sharedScalar
    }
});

sharedScalar requires you to pass a name to identify the shared variable (as the API needs to map multiple calls to the Create method by multiple threads to the same variable). Once created, you can easily use sharedScalar similarly to a regular scalar, with the caveat that you should call Set to set the variable:

using (var sharedScalar = DotMP.Shared.Create("sharedScalar", 0))
{
    int scalar = sharedScalar;

    sharedScalar.Set(4);
}

It is worth noting that calling Set does not synchronize threads, and is not implemented atomically. It behaves very similarly to if you were to have created the variable outside of a ParallelRegion and captured the variable via closure.

Shared Enumerables

To create a shared enumerable, you can use the shared enumerable factory. As with regular shared memory, it implements IDisposable and should optimally be used within a using region. If not, you need to call Dispose() to free the memory when you're done.

DotMP.Parallel.ParallelRegion(() =>
{
    using (var sharedVector = DotMP.SharedEnumerable.Create("sharedVector", new double[1024]))
    {
        // use sharedVector
    }
});

Shared enumerables allow you to pass in either an array or a System.List<T> as a value. As with shared scalars, you can implicitly cast a shared enumerable to its native datatype. However, the SharedEnumerable class provides a [] operator to allow for direct indexing of values:

using (var sharedVector = DotMP.SharedEnumerable.Create("sharedVector", new double[1024]))
{
    double[] vector = sharedVector;

    sharedVector[DotMP.Parallel.GetThreadNum()]++;
}

Again, this behaves very similarly to if you were to create an enumerable outside of the parallel region and capture it via closure, and should be handled as such.