Data.IORef
| Авторские права | (c) Университет Глазго 2001 |
|---|---|
| Лицензия | BSD-стиль (см. файл libraries/base/LICENSE) |
| Поддержка | libraries@haskell.org |
| Устойчивость | экспериментальная |
| Переносимость | переносимая |
| Безопасный Haskell | Надежный |
| Язык | Haskell2010 |
Содержание
Описание
Мутабельные ссылки в монаде IO.
IORefs
Мутабельная переменная в IO монаде
Примеры
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