Spec-Zone.ru › Haskell 8

Control.Concurrent.MVar

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

Содержание

  • MVars

Описание

Изменяемое местоположение MVar t, которое либо пусто, либо содержит значение типа t. Оно имеет две основные операции: putMVar, которая заполняет MVar, если оно пусто, и блокирует в противном случае, и takeMVar, которая опустошает MVar, если оно заполнено, и блокирует в противном случае. Они могут использоваться различными способами:

  1. В качестве синхронизированных изменяемых переменных,
  2. В качестве каналов, с takeMVar и putMVar в качестве приема и отправки, и
  3. В качестве бинарного семафора MVar (), с takeMVar и putMVar в качестве ожидания и сигнала.

Они были введены в статье "Concurrent Haskell" Саймоном Пейтоном Джонсом, Эндрю Гордоном и Сигбьорном Финне, хотя некоторые детали их реализации с тех пор изменились (в частности, запись в полное MVar раньше вызывала ошибку, а теперь просто блокируется.)

Применимость

MVar предлагают большую гибкость, чем IORef , но меньшую гибкость, чем STM. Они подходят для создания примитивов синхронизации и выполнения простого межпоточного взаимодействия; однако они очень простые и подвержены гонкам, тупикам или необработанным исключениям. Не используйте их, если вам необходимо выполнять более крупные атомарные операции, такие как чтение из нескольких переменных: используйте STM вместо этого.

В частности, «большие» функции в этом модуле (swapMVar, withMVar, modifyMVar_ и modifyMVar ) просто представляют собой композицию takeMVar , за которой следует putMVar с безопасностью от исключений. Они гарантируют атомарность только в том случае, если все остальные потоки выполняют takeMVar перед putMVar, иначе они могут заблокироваться.

Честность

Ни один поток не может быть заблокирован неопределенно на MVar, если другой поток не удерживает этот MVar неопределенно. Одним из распространенных способов обеспечения этого гарантии честности является обслуживание потоков, заблокированных на MVar, в порядке очереди «первый пришёл – первый обслужен», но это не гарантируется в семантике.

Особенности

Как и многие другие структуры данных Haskell, MVar ленивы. Это означает, что если вы поместите дорогостоящую невычисленную функцию в MVar, поток, который её использует, вычислит её, а не тот, который её создал. Убедитесь, что вы evaluate значения, помещенные в MVar , в нужное нормальное представление, или используйте жёсткий MVar, предоставляемый пакетом strict-concurrency.

Порядок

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

Пример

Рассмотрим следующую конкурентную структуру данных, пропускающий канал. Это канал для прерывистого источника информации с высокой пропускной способностью (например, события движения мыши.) Запись в канал никогда не блокирует, а чтение из канала возвращает только последнее значение или блокируется, если новых значений нет. Поддержка нескольких читателей с помощью операции dupSkipChan.

Пропускающий канал — это пара MVar. Первый MVar содержит текущее значение и список семафоров, которые нужно уведомить при изменении значения. Второй MVar — это семафор для данного читателя: он заполнен, если в канале есть значение, которое этот читатель ещё не прочитал, и пуст в противном случае.

    data SkipChan a = SkipChan (MVar (a, [MVar ()])) (MVar ())

    newSkipChan :: IO (SkipChan a)
    newSkipChan = do
        sem <- newEmptyMVar
        main <- newMVar (undefined, [sem])
        return (SkipChan main sem)

    putSkipChan :: SkipChan a -> a -> IO ()
    putSkipChan (SkipChan main _) v = do
        (_, sems) <- takeMVar main
        putMVar main (v, [])
        mapM_ (sem -> putMVar sem ()) sems

    getSkipChan :: SkipChan a -> IO a
    getSkipChan (SkipChan main sem) = do
        takeMVar sem
        (v, sems) <- takeMVar main
        putMVar main (v, sem:sems)
        return v

    dupSkipChan :: SkipChan a -> IO (SkipChan a)
    dupSkipChan (SkipChan main _) = do
        sem <- newEmptyMVar
        (v, sems) <- takeMVar main
        putMVar main (v, sem:sems)
        return (SkipChan main sem)

Этот пример был адаптирован из оригинальной статьи "Concurrent Haskell". Для получения дополнительных примеров использования MVar для построения примитивов синхронизации высокого уровня, см. Chan и QSem.

MVars

data MVar a Источник

MVar (произносится "эм-вар") — это синхронизируемая переменная, используемая для межпоточной коммуникации. Её можно представить как коробку, которая может быть пустой или заполненной.

Примеры
Примеры деталей
Eq (MVar a)

С тех пор: base-4.1.0.0

Детали примера

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

Методы

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

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

newEmptyMVar :: IO (MVar a) Источник

Создать MVar, которая изначально пуста.

newMVar :: a -> IO (MVar a) Источник

Создать MVar, которая содержит предоставленное значение.

takeMVar :: MVar a -> IO a Источник

Возвращает содержимое MVar. Если MVar в данный момент пусто, takeMVar будет ожидать, пока она не заполнится. После takeMVar MVar остаётся пустой.

Есть две другие важные особенности takeMVar:

  • takeMVar выполняет одиночное пробуждение. То есть, если несколько потоков заблокированы в takeMVar, и MVar становится заполненной, только один поток будет разбужен. Выполнение гарантирует, что разбуженный поток завершит свою операцию takeMVar.
  • Когда несколько потоков заблокированы на MVar, они разбуживаются в порядке очереди FIFO. Это полезно для обеспечения свойств честности абстракций, построенных с использованием MVar.

putMVar :: MVar a -> a -> IO () Источник

Поместить значение в MVar. Если MVar в данный момент заполнено, putMVar будет ожидать, пока она не станет пустой.

Есть две другие важные особенности putMVar:

  • putMVar выполняет одиночное пробуждение. То есть, если несколько потоков заблокированы в putMVar, и MVar становится пустой, только один поток будет разбужен. Выполнение гарантирует, что разбуженный поток завершит свою операцию putMVar.
  • Когда несколько потоков заблокированы на MVar, они разбуживаются в порядке очереди FIFO. Это полезно для обеспечения свойств честности абстракций, построенных с использованием MVar.

readMVar :: MVar a -> IO a Источник

Атомарно прочитать содержимое MVar. Если MVar в данный момент пусто, readMVar будет ожидать, пока она не заполнится. readMVar гарантировано получит следующее putMVar.

readMVar выполняет множественное пробуждение, поэтому, когда несколько читателей заблокированы на MVar, все они разбуживаются одновременно.

Примечание о совместимости: До версии base 4.7, readMVar была комбинацией takeMVar и putMVar. Это означало, что при попытке других потоков putMVar readMVar мог заблокироваться. Кроме того, readMVar не получал следующее putMVar , если уже был ожидающий поток, заблокированный на takeMVar. Старое поведение может быть восстановлено путём реализации 'readMVar следующим образом:

 readMVar :: MVar a -> IO a
 readMVar m =
   mask_ $ do
     a <- takeMVar m
     putMVar m a
     return a

swapMVar :: MVar a -> a -> IO a Source

Извлечь значение из MVar, поместить новое значение в MVar и вернуть извлечённое значение. Эта функция атомарна только в случае отсутствия других производителей для данного MVar.

tryTakeMVar :: MVar a -> IO (Maybe a) Source

Неблокирующая версия takeMVar. Функция tryTakeMVar возвращается немедленно, с Nothing, если MVar была пустой, или Just a, если MVar была заполнена содержимым a. После tryTakeMVar, MVar остаётся пустой.

tryPutMVar :: MVar a -> a -> IO Bool Source

Неблокирующая версия putMVar. Функция tryPutMVar пытается поместить значение a в MVar, возвращая True, если операция была успешной, или False в противном случае.

isEmptyMVar :: MVar a -> IO Bool Source

Проверить, пуст ли данный MVar.

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

withMVar :: MVar a -> (a -> IO b) -> IO b Source

withMVar — это защищённый от исключений обертка для работы со содержимым MVar. Эта операция защищена от исключений: она заменит исходное содержимое MVar, если возникнет исключение (см. Control.Exception). Однако она атомарна только если нет других производителей для данного MVar.

withMVarMasked :: MVar a -> (a -> IO b) -> IO b Source

Подобно withMVar, но действие IO во втором аргументе выполняется с замаскированными асинхронными исключениями.

Since: base-4.7.0.0

modifyMVar_ :: MVar a -> (a -> IO a) -> IO () Source

Защищённая от исключений обертка для изменения содержимого MVar. Как и withMVar, modifyMVar заменит исходное содержимое MVar, если во время операции произойдёт исключение. Эта функция атомарна только при отсутствии других производителей для этого MVar.

modifyMVar :: MVar a -> (a -> IO (a, b)) -> IO b Source

Небольшое изменение modifyMVar_, позволяющее вернуть значение (b) дополнительно к изменённому значению MVar.

modifyMVarMasked_ :: MVar a -> (a -> IO a) -> IO () Source

Подобно modifyMVar_, но действие IO во втором аргументе выполняется с замаскированными асинхронными исключениями.

Since: base-4.6.0.0

modifyMVarMasked :: MVar a -> (a -> IO (a, b)) -> IO b Source

Подобно modifyMVar, но действие IO во втором аргументе выполняется с замаскированными асинхронными исключениями.

Since: base-4.6.0.0

tryReadMVar :: MVar a -> IO (Maybe a) Source

Неблокирующая версия readMVar. Функция tryReadMVar возвращается немедленно, с Nothing, если MVar была пустой, или Just a, если MVar была заполнена содержимым a.

Since: base-4.7.0.0

mkWeakMVar :: MVar a -> IO () -> IO (Weak (MVar a)) Source

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

Since: base-4.6.0.0

addMVarFinalizer :: MVar a -> IO () -> IO () Source

Устарело: используйте mkWeakMVar вместо этого

© 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/Control-Concurrent-MVar.html

Spec-Zone.ru

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