Нужен ли барьер памяти (.net x86 или x64) при разыменовании полей? - PullRequest
3 голосов
/ 15 января 2011

В коде, подобном следующему, если Proc1 и Proc2 выполняются одновременно на разных процессорах, возможно ли для ThingVal2 получить значение, отличное от 5 (например, ноль)?

Class SimpleThing
    Public X As Integer
    Sub New(ByVal value As Integer)
        X = value
    End Sub
End Class
Class ConcurrencyTest
    Dim Thing1 As New SimpleThing(5)
    Dim Thing2 As New SimpleThing(0)
    Dim ThingRef As SimpleThing = Thing1
    Dim ThingVal1, ThingVal2 As Integer
    Sub Proc1()
        Thing2.X = 5
        Threading.Thread.MemoryBarrier()
        ThingRef = Thing2
    End Sub
    Sub Proc2()
        ThingVal1 = Thing2.X
        ThingVal2 = ThingRef.X
    End Sub
End Class

Я знаю, что в слабой модели, такой как IA64, существует реальная возможность того, что Proc2 может увидеть ThingRef как измененный, но не увидит поле X Thing2 как сделавшее это. Существует ли такой риск для приложения .Net, работающего на x86 или x64? Если Proc1 создал новый экземпляр SimpleThing, установите его поле X равным 5, а затем установите ThingRef для указания на него, будет ли этого достаточно, чтобы избежать опасности, или возможно, что новая вещь будет размещена в строке кэша, которая было передано что-то еще, что поток Proc2 получил доступ?

Распространенная парадигма с многопоточным кодом - это создание неизменяемого объекта и установка изменяемой ссылки для указания на него (возможно, с использованием Interlocked.CompareExchange). Всегда ли безопасно в x86 / x64 читать неизменяемый тип без учета многопоточности или это может вызвать проблемы? Если последнее, что является предпочтительным способом в vb.net, чтобы гарантировать надежное поведение?

Кроме того, есть ли способ указать, что код должен выполняться таким образом, чтобы такие проблемы не возникали (например, ограничение выполнения одним ядром на чем-то вроде IA64, которое иначе не могло бы гарантировать правильную работу)?

1 Ответ

0 голосов
/ 15 января 2011

ОК, вы задали много вопросов.Я постараюсь ответить на то, что знаю.

-1.ad ваш пример кода:

CLR, так как 2.0 заказал магазины.Это означает, что ваш ThingVal всегда будет 5 на x86 / x64.Наверняка.Я не пробовал его на реальном IA64, но он должен работать и на IA64, потому что CLR должен обеспечивать упорядоченную запись на всех платформах и должно быть достаточно для вашего простого примера.

-2.ad IA64 против x86 / x64:

x86 / x64 имеет другую семантику памяти, и такого риска нет, как в IA64.Единственная возможная проблема здесь заключается в том, что вы на самом деле используете язык более высокого уровня, и если он использует оптимизирующий компилятор (как это делает C ++), вы не можете ничего предсказать, не зная точно, как компилятор выполняет свои оптимизации.Недокументированное: VB не выполняет глобальные оптимизации и т. Д., Поэтому ваш код должен быть безопасным.

-3.ad immutable:

Если вы действительно только что прочитали его и он действительно неизменен, это безопасно.

-4.ad одно ядро:

Вы можете установить сродство потока.Это стандартное свойство каждого потока и определяет, на каких процессорах поток может работать.(Настройка сходства потоков в .net напрямую изменяет сходство в операционной системе.) Но это заставляет вашу программу работать медленно.

Также вы можете переключиться на C # и использовать ключевое слово volatile .Это поможет вам жить легче, поскольку вносит любые изменения в переменную volatile, которые сразу же видят все процессоры, и это, в свою очередь, решит все возможные проблемы, которые вы здесь представили.К сожалению, VB не предоставляет это ключевое слово.

...