Хотя в D предпочтительным методом организации
многопоточности является использование immutable
данных и синхронизация посредством обмена сообщениями,
язык также предлагает встроенную поддержку примитивов
синхронизации и поддержку на уровне типов, с применением
ключевого слова shared
для обозначения объектов,
доступ к которым осуществляется из нескольких потоков.
Квалификатор типа shared
позволяет пометить переменные,
разделяемые между различными потоками:
shared(int)* p = new int;
int* t = p; // ОШИБКА
Например, функция std.concurrency.send
позволяет передавать
только immutable
или shared
данные и копирует сообщение
перед отправкой. shared
транзитивно, и если класс или структура
помечены shared
, все их члены также будут помечены.
Обратите внимание, static
-переменные по умолчанию не
являются shared
, т.к. хранятся в локальном хранилище потока
(TLS), и каждый поток получает собственную переменную.
Блоки synchronized
позволяют указать компилятору необходимость
создания критической секции, в которую потоки могут входить
только по одному.
synchronized {
importStuff();
}
При определении функций-членов класса, такие
блоки можно разграничить посредством членов-мьютексов,
с использованием synchronized(член1, член2)
,
для снижения нагрузки на ресурс. Компилятор D
автоматически вставит критические секции. Также можно весь класс пометить как synchronized
,
в этом случае компилятор гарантирует, что только
один поток имеет доступ к объекту в отдельно взятый
момент.
Атомарные операции над shared
-переменными
можно производить посредством вспомогательной
функции core.atomic.atomicOp
:
shared int test = 5;
test.atomicOp!"+="(4);