При совместном использовании IORef безопасно ли читать с readIORef, пока я пишу с помощью atomicModifyIORef? - PullRequest
9 голосов
/ 17 февраля 2012

Если я разделяю IORef между несколькими потоками и использую atomicModifyIORef для записи в него:

atomicModifyIORef ref (\_ -> (new, ()))

Безопасно ли читать значение со старым readIORef? Или есть вероятность, что readIORef вернет старое значение в другом потоке после того, как atomicModifyIORef изменило его?

Я думаю, что это подразумевает документация:

atomicModifyIORef действует как барьер для переупорядочения. множественный Операции atomicModifyIORef выполняются в строгом программном порядке. atomicModifyIORef никогда не наблюдается раньше, чем раньше (в программном порядке) операции IORef или после любых последующих IORef операции.

Я просто хочу быть уверен.

Ответы [ 3 ]

14 голосов
/ 17 февраля 2012

atomicModifyIORef гарантирует, что ничего не происходит между атомарным чтением и следующей атомарной записью, что делает всю операцию атомарной. В цитируемом вами комментарии просто говорится, что atomicModifyIORef s никогда не будет происходить параллельно, и что оптимизатор не будет пытаться переупорядочить операторы для оптимизации программы (отдельные операции чтения и записи можно безопасно перемещать в некоторых случаях; например, в a' <- read a; b' <- read b; write c $ a' + b' показания можно смело переупорядочить)

readIORef уже атомарный, так как выполняет только одну операцию.

Однако вы обсуждаете другую проблему. Да, если atomicModify происходит в t=3ms, а read происходит в t=4ms, вы получите измененное значение. Тем не мение; потоки не гарантированно работают параллельно, поэтому, если вы это сделаете (псевдокод):

forkIO $ do
  sleep 100 ms
  atomicModify
sleep 1000 ms
read

... нет никакой гарантии, что чтение произойдет после изменения (хотя это крайне маловероятно для современных ОС), потому что операционная система может решить запланировать новый недолговечный поток таким образом, что это может происходить параллельно.

3 голосов
/ 17 февраля 2012

Вы не хотите использовать IORef с несколькими потоками, поскольку они практически не дают никаких гарантий. Я обычно использую MVar вместо этого.

3 голосов
/ 17 февраля 2012

Если вы хотите поделиться изменяемой ссылкой между несколькими потоками, вам действительно следует использовать TVar вместо IORef. Вот и вся мотивация для TVars. Вы используете TVars почти так же, как IORef, но любой доступ или изменение должны быть заключены в блок atomically, который всегда гарантированно является атомарной операцией.

...