Поделиться барьером между потоками в D

У меня чертовски много времени, чтобы заставить синхронизацию барьера в D работать правильно. В настоящее время я не получаю никаких ошибок компилятора, однако каждый раз, когда он достигает барьера, я получаю ошибку сегментации. Вот в основном что у меня есть:

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();
}

Я пытался полностью определить барьер в основной функции, но dmd жалуется:

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

Я также пытался передать его как общую переменную, и я получаю следующее:

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

person jdeters    schedule 26.03.2016    source источник
comment
Маркировка барьера как __gshared заставляет его работать для меня (в Windows).   -  person sigod    schedule 26.03.2016


Ответы (1)


Глобальные переменные по умолчанию являются локальными для потока в D. Когда вы устанавливаете barrier в своем основном потоке, вы устанавливаете его только в основном потоке; для других потоков barrier будет null.

Вы можете пометить barrier как __gshared, чтобы сделать его глобальным для потока, хотя это немного хак:

__gshared Barrier barrier;

Как вы обнаружили, функция создания потока позволяет передавать только данные, помеченные как shared. Однако, поскольку функция Barrier.wait не помечена как shared, вы не можете вызывать ее с объектом shared(Barrier), что делает ее практически бесполезной. В качестве другого хака вы можете сначала преобразовать его в unshared перед вызовом wait:

(cast()barrier).wait();
person Colonel Thirty Two    schedule 26.03.2016
comment
Ах! Я знал, что это будет что-то с управлением памятью в D, чего я не понимал. Теперь вы описали оба из них как хаки. Это то, как такой обмен будет выполняться в D, или есть нехакерский способ, с помощью которого я могу это сделать? - person jdeters; 26.03.2016
comment
shared немного... занижено. Моя интерпретация заключается в том, что любые данные, совместно используемые потоками, должны быть shared, только shared методов могут вызываться для shared объектов, а приведение к неразделяемым определяется только в том случае, если поток имеет монопольный доступ к объекту (например, защищенному мьютексом). Таким образом, такие функции, как Barrier.wait, Mutex.lock и т. д., должны быть shared, но это не так, что, по моему мнению, является недостатком стандартной библиотеки. - person Colonel Thirty Two; 26.03.2016
comment
@ColonelThirtyTwo Для этого вы должны создать тикет в системе отслеживания ошибок. - person sigod; 27.03.2016