5

I'm having a heck of a time trying to get the barrier sync in D to work properly. I'm currently not getting any compiler errors, however every time it reaches the barrier I get a segmentation fault. Here's basically what I have:

import std.stdio;
import std.conv;
import std.concurrency;
import core.thread;
import core.sync.barrier;

//create barrier
Barrier barrier;

void the_thread()
{
    barrier.wait(); //I get a segmentation fault here
}

void main(string[] args)
{
    int threads = to!int(args[1]); //number of threads

    //init barrier
    barrier = new Barrier(threads);

    //launch threads
    foreach(i; 0 .. threads)
    {
       spawn(&the_thread);
    }
    thread_joinAll();
}

I've tried defining the barrier completely in the main function, but dmd complains:

static assert  "Aliases to mutable thread-local data not allowed."

I've also tried passing it as a shared variable and I get this:

non-shared method core.sync.barrier.Barrier.wait is not callable using a shared object
jdeters
  • 53
  • 3

1 Answers1

4

Global variables are thread-local by default in D. When you set barrier in your main thread, you only set it in the main thread; for the other threads, barrier will be null.

You can mark barrier as __gshared to make it thread-global, though it's a bit of a hack:

__gshared Barrier barrier;

The thread spawn function only allows passing data marked as shared, as you've discovered. However, since the Barrier.wait function is not marked as shared, you can't call it with a shared(Barrier) object, making it mostly useless. As another hack, you can cast it to unshared first before calling wait:

(cast()barrier).wait();
Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
  • Ah! I knew it would be something with memory management in D that I didn't understand. Now, you've described both of these as hacks. Is this how this sort of sharing would be accomplished in D or is there a non-hackish way that I can accomplish this with? – jdeters Mar 26 '16 at 18:57
  • `shared` is a bit... underspecified. My interpretation is that any data being shared across threads needs to be `shared`, only `shared` methods can be called on `shared` objects, and casting to unshared is only defined if the thread has exclusive access to an object (ex. protected by a mutex). So functions like `Barrier.wait`, `Mutex.lock`, etc. should be `shared`, but they're not, which is IMO a deficiency in the standard library. – Colonel Thirty Two Mar 26 '16 at 19:18
  • @ColonelThirtyTwo You should create ticket in bug tracker for this. – sigod Mar 27 '16 at 11:00