Spec-Zone.ru › Haskell 8

Data.IORef

Авторские права (c) Университет Глазго 2001
Лицензия BSD-стиль (см. файл libraries/base/LICENSE)
Поддержка libraries@haskell.org
Устойчивость экспериментальная
Переносимость переносимая
Безопасный Haskell Надежный
Язык Haskell2010

Содержание

  • IORefs
    • Модель памяти

Описание

Мутабельные ссылки в монаде IO.

IORefs

data IORef a Источник

Мутабельная переменная в IO монаде

Примеры
Подробности примеров
Eq (IORef a)

Равенство указателей.

С: base-4.0.0.0

Подробности примера

Определено в GHC.IORef

Методы

(==) :: IORef a -> IORef a -> Bool Источник

(/=) :: IORef a -> IORef a -> Bool Источник

newIORef :: a -> IO (IORef a) Источник

Создать новую IORef

readIORef :: IORef a -> IO a Источник

Прочитать значение IORef

writeIORef :: IORef a -> a -> IO () Источник

Записать новое значение в IORef

modifyIORef :: IORef a -> (a -> a) -> IO () Источник

Изменить содержимое IORef.

Обратите внимание, что modifyIORef не применяет функцию строго. Это означает, что если программа вызывает modifyIORef много раз, но редко использует значение, задержки будут накапливаться в памяти, что приведет к утечке памяти. Это распространённая ошибка при использовании IORef в качестве счётчика. Например, следующее, вероятно, приведёт к переполнению стека:

ref <- newIORef 0
replicateM_ 1000000 $ modifyIORef ref (+1)
readIORef ref >>= print

Чтобы избежать этой проблемы, используйте modifyIORef'.

modifyIORef' :: IORef a -> (a -> a) -> IO () Источник

Строгая версия modifyIORef

С: base-4.6.0.0

atomicModifyIORef :: IORef a -> (a -> (a, b)) -> IO b Источник

Атомарно изменяет содержимое IORef.

Эта функция полезна для безопасного использования IORef в многопоточной программе. Если у вас только один IORef, то использование atomicModifyIORef для доступа и изменения предотвратит гонки.

Расширение атомарности на несколько IORef представляет собой проблему, поэтому рекомендуется использовать MVar, если вам требуется что-то более сложное.

atomicModifyIORef не применяет функцию строго. Это важно знать, даже если вы просто заменяете значение. Например, это приведёт к утечке памяти:

ref <- newIORef '1'
forever $ atomicModifyIORef ref (\_ -> ('2', ()))

Чтобы избежать этой проблемы, используйте atomicModifyIORef' или atomicWriteIORef.

atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b Source

Строгая версия atomicModifyIORef. Это принуждает к вычислению как значения, хранящегося в IORef, так и возвращаемого значения. Новое значение устанавливается в IORef до принудительного вычисления возвращаемого значения. Таким образом,

atomicModifyIORef' ref (x -> (x+1, undefined))

увеличит IORef и затем вызовет исключение в потоке вызова.

Since: base-4.6.0.0

atomicWriteIORef :: IORef a -> a -> IO () Source

Вариант writeIORef с свойством "барьера для переупорядочивания", которым обладает atomicModifyIORef.

Since: base-4.6.0.0

mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a)) Source

Создаёт Weak указатель на IORef, используя второй аргумент в качестве финализатора, который выполняется при сборе мусора IORef.

Модель памяти

В конкурирующей программе операции IORef могут отображаться в другом порядке для другого потока, в зависимости от модели памяти используемой архитектуры процессора. Например, на x86 загрузка может перемещаться вперёд по отношению к сохранению. Поэтому в следующем примере:

import Data.IORef
import Control.Monad (unless)
import Control.Concurrent (forkIO, threadDelay)

maybePrint :: IORef Bool -> IORef Bool -> IO ()
maybePrint myRef yourRef = do
  writeIORef myRef True
  yourVal <- readIORef yourRef
  unless yourVal $ putStrLn "critical section"

main :: IO ()
main = do
  r1 <- newIORef False
  r2 <- newIORef False
  forkIO $ maybePrint r1 r2
  forkIO $ maybePrint r2 r1
  threadDelay 1000000

возможна ситуация, когда строка "critical section" выводится дважды, даже если нет переплетения операций двух потоков, которое позволило бы такой результат. Модель памяти x86 позволяет readIORef произойти до более раннего writeIORef.

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

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

© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/8.10.2/docs/html/libraries/base-4.14.1.0/Data-IORef.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API