Spec-Zone.ru › Haskell 8

GHC.Conc.Sync

Copyright (c) The University of Glasgow 1994-2002
License see libraries/base/LICENSE
Maintainer cvs-ghc@haskell.org
Stability internal
Portability non-portable (GHC extensions)
Safe Haskell Unsafe
Language Haskell2010

Содержание

  • Разветвление и тому подобное
  • Счётчик выделения и квота
  • TVars
  • Разное

Описание

Основные средства параллелизма.

data ThreadId Source

A ThreadId is an abstract type representing a handle to a thread. ThreadId is an instance of Eq, Ord and Show, where the Ord instance implements an arbitrary total ordering over ThreadIds. The Show instance lets you convert an arbitrary-valued ThreadId to string form; showing a ThreadId value is occasionally useful when debugging or diagnosing the behaviour of a concurrent program.

Примечание: в GHC, если у вас есть ThreadId, вы по существу имеете указатель на сам поток. Это означает, что сам поток не может быть удалён сборщиком мусора, пока вы не отбросите ThreadId. Надеюсь, этот недостаток будет исправлен позже.

Конструкторы

ThreadId ThreadId#
Экземпляры
Подробности о экземплярах
Eq ThreadId

С версии: base-4.2.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

(==) :: ThreadId -> ThreadId -> Bool Source

(/=) :: ThreadId -> ThreadId -> Bool Source

Ord ThreadId

С версии: base-4.2.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

compare :: ThreadId -> ThreadId -> Ordering Source

(<) :: ThreadId -> ThreadId -> Bool Source

(<=) :: ThreadId -> ThreadId -> Bool Source

(>) :: ThreadId -> ThreadId -> Bool Source

(>=) :: ThreadId -> ThreadId -> Bool Source

max :: ThreadId -> ThreadId -> ThreadId Source

min :: ThreadId -> ThreadId -> ThreadId Source

Show ThreadId

С версии: base-4.2.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

showsPrec :: Int -> ThreadId -> ShowS Source

show :: ThreadId -> String Source

showList :: [ThreadId] -> ShowS Source

Разветвление и тому подобное

forkIO :: IO () -> IO ThreadId Source

Создаёт новый поток для выполнения вычисления IO, переданного в качестве первого аргумента, и возвращает ThreadId вновь созданного потока.

Новый поток будет лёгким, несвязанным потоком. Внешние вызовы, сделанные этим потоком, не гарантируется, что будут сделаны каким-либо конкретным потоком ОС; если вам необходимо, чтобы внешние вызовы выполнялись конкретным потоком ОС, используйте forkOS вместо этого.

Новый поток наследует замаскированное состояние родительского (см. mask).

Вновь созданный поток имеет обработчик исключений, который игнорирует исключения BlockedIndefinitelyOnMVar, BlockedIndefinitelyOnSTM и ThreadKilled, и передаёт все остальные исключения обработчику неперехваченных исключений.

forkIOWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId Source

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

 ... mask_ $ forkIOWithUnmask $ \unmask ->
                catch (unmask ...) handler

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

Обратите внимание, что функция unmask, переданная дочернему потоку, должна использоваться только в этом потоке; поведение не определено, если она вызывается в другом потоке.

С версии: base-4.4.0.0

forkOn :: Int -> IO () -> IO ThreadId Source

Подобно forkIO, но позволяет указать, на какой возможности должен выполняться поток. В отличие от потока forkIO, поток, созданный с помощью forkOn, будет оставаться на той же возможности в течение всего своего жизненного цикла (потоки forkIO могут перемещаться между возможностями в соответствии с политикой планирования). forkOn полезно для переопределения политики планирования, когда заранее известно, как лучше распределить потоки.

Аргумент Int задаёт номер возможности (см. getNumCapabilities). Обычно возможности соответствуют физическим процессорам, но точное поведение зависит от реализации. Значение, переданное в forkOn, интерпретируется по модулю общего числа возможностей, возвращаемого getNumCapabilities.

Примечание GHC: количество возможностей задаётся опцией +RTS -N при запуске программы. Возможности можно привязать к фактическим ядрам процессора с помощью +RTS -qa, если операционная система поддерживает это, хотя на практике это обычно не требуется (и в некоторых случаях может даже ухудшить производительность — рекомендуется проводить эксперименты).

С момента: base-4.4.0.0

forkOnWithUnmask :: Int -> ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId Источник

Подобно forkIOWithUnmask, но дочерний поток привязывается к заданному процессору, как и в forkOn.

С момента: base-4.4.0.0

numCapabilities :: Int Источник

значение, передаваемое флагу +RTS -N. Это количество потоков Haskell, которые могут выполняться одновременно в любой данный момент, и обычно устанавливается равным количеству физических ядер процессора на машине.

Строго говоря, лучше использовать getNumCapabilities, так как количество возможностей может изменяться во время выполнения.

getNumCapabilities :: IO Int Источник

Возвращает количество потоков Haskell, которые могут выполняться одновременно (на отдельных физических процессорах) в любой данный момент. Чтобы изменить это значение, используйте setNumCapabilities.

С момента: base-4.4.0.0

setNumCapabilities :: Int -> IO () Источник

Устанавливает количество потоков Haskell, которые могут выполняться одновременно (на отдельных физических процессорах) в любой данный момент. Значение, переданное в forkOn интерпретируется по модулю этого значения. Начальное значение задаётся флагом выполнения +RTS -N.

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

С момента: base-4.5.0.0

getNumProcessors :: IO Int Источник

Возвращает количество ЦП, имеющихся в системе.

С момента: base-4.5.0.0

numSparks :: IO Int Источник

Возвращает количество искр, в настоящее время находящихся в локальном пуле искр.

childHandler :: SomeException -> IO () Источник

myThreadId :: IO ThreadId Источник

Возвращает ThreadId вызывающего потока (только GHC).

killThread :: ThreadId -> IO () Источник

killThread вызывает исключение ThreadKilled в заданном потоке (только GHC).

killThread tid = throwTo tid ThreadKilled

throwTo :: Exception e => ThreadId -> e -> IO () Источник

throwTo вызывает произвольное исключение в целевом потоке (только GHC).

Доставка исключений синхронизируется между исходным и целевым потоком: throwTo не возвращается до тех пор, пока исключение не будет вызвано в целевом потоке. Таким образом, вызывающий поток может быть уверен, что целевой поток получил исключение. Доставка исключений также является атомарной по отношению к другим исключениям. Атомарность полезна при работе с гонками: например, если есть два потока, которые могут убить друг друга, гарантируется, что только один из потоков сможет убить другого.

Любая работа, которую выполнял целевой поток при возникновении исключения, не теряется: вычисление приостанавливается до тех пор, пока это не потребуется другому потоку.

Если целевой поток в настоящее время выполняет внешний вызов, то исключение не будет вызвано (и, следовательно, throwTo не вернётся) до завершения вызова. Это справедливо независимо от того, находится ли вызов внутри mask или нет. Однако в GHC внешний вызов может быть помечен как interruptible, в этом случае throwTo заставит RTS попытаться заставить вызов вернуть значение; см. документацию GHC для получения дополнительной информации.

Важно: поведение throwTo отличается от описанного в статье "Асинхронные исключения в Haskell" (http://research.microsoft.com/~simonpj/Papers/asynch-exns.htm). В статье throwTo неблокирующее; но реализация библиотеки использует более синхронный дизайн, в котором throwTo не возвращается до тех пор, пока исключение не будет получено целевым потоком. О компромиссе говорится в разделе 9 статьи. Как и любая блокирующая операция, throwTo поэтому прерывиста (см. раздел 5.3 статьи). Однако, в отличие от других прерывистых операций, throwTo всегда прерывиста, даже если она фактически не блокирует.

Нет гарантии, что исключение будет доставлено быстро, хотя среда выполнения постарается гарантировать, что произвольные задержки не возникнут. В GHC исключение может быть вызвано только тогда, когда поток достигает безопасной точки, где безопасная точка — это место, где происходит выделение памяти. Некоторые циклы не выполняют никакого выделения памяти внутри цикла и поэтому не могут быть прерваны throwTo.

Если целевой объект throwTo является вызывающим потоком, то поведение аналогично throwIO, за исключением того, что исключение выбрасывается как асинхронное исключение. Это означает, что если есть окружающее чистое вычисление, что было бы так, если бы текущая операция IO находилась внутри unsafePerformIO или unsafeInterleaveIO, это вычисление не заменяется исключением навсегда, а приостанавливается так, как если бы оно получило асинхронное исключение.

Обратите внимание, что если throwTo вызывается с текущим потоком как целевым, исключение будет вызвано, даже если поток в настоящее время находится внутри mask или uninterruptibleMask.

par :: a -> b -> b infixr 0 Источник

pseq :: a -> b -> b infixr 0 Источник

runSparks :: IO () Источник

Внутренняя функция, используемая RTS для запуска искр.

yield :: IO () Источник

Действие yield позволяет (вынуждает в реализации кооперативной многозадачности) контекстное переключение на любой другой в данный момент готовый к работе поток (если таковой имеется), и это иногда полезно при реализации абстракций конкурентности.

labelThread :: ThreadId -> String -> IO () Source

labelThread сохраняет строку в качестве идентификатора для этого потока, если вы создали RTS с поддержкой отладки. Этот идентификатор будет использоваться в выходных данных отладки для упрощения различения различных потоков (в противном случае у вас будет только адрес объекта состояния потока в куче).

Другие приложения, такие как графический отладчик Concurrent Haskell Debugger (http://www.informatik.uni-kiel.de/~fhu/chd/), также могут перегрузить labelThread для своих целей.

mkWeakThreadId :: ThreadId -> IO (Weak ThreadId) Source

Создает слабый указатель на ThreadId. Это может быть важно, если вы хотите сохранить ссылку на ThreadId, позволяя при этом потоку получать семейство исключений BlockedIndefinitely (например, BlockedIndefinitelyOnMVar). Удержание обычной ссылки ThreadId предотвратит доставку исключений BlockedIndefinitely, поскольку ссылка может использоваться в качестве цели throwTo в любое время, что разблокирует поток.

Удержание Weak ThreadId, с другой стороны, не будет препятствовать получению потоком исключений BlockedIndefinitely. Все еще возможно бросить исключение в Weak ThreadId, но вызывающий абонент должен сначала использовать deRefWeak для определения того, существует ли еще поток.

Since: base-4.6.0.0

data ThreadStatus Source

Текущий статус потока

Краткое описание конструкторов

ThreadRunning

поток в данный момент выполняется или готов к выполнению

ThreadFinished

поток завершен

ThreadBlocked BlockReason

поток заблокирован на некотором ресурсе

ThreadDied

поток получил неперехваченное исключение

Instances
Instances details
Eq ThreadStatus

Since: base-4.3.0.0

Instance details

Defined in GHC.Conc.Sync

Methods

(==) :: ThreadStatus -> ThreadStatus -> Bool Source

(/=) :: ThreadStatus -> ThreadStatus -> Bool Source

Ord ThreadStatus

Since: base-4.3.0.0

Instance details

Defined in GHC.Conc.Sync

Methods

compare :: ThreadStatus -> ThreadStatus -> Ordering Source

(<) :: ThreadStatus -> ThreadStatus -> Bool Source

(<=) :: ThreadStatus -> ThreadStatus -> Bool Source

(>) :: ThreadStatus -> ThreadStatus -> Bool Source

(>=) :: ThreadStatus -> ThreadStatus -> Bool Source

max :: ThreadStatus -> ThreadStatus -> ThreadStatus Source

min :: ThreadStatus -> ThreadStatus -> ThreadStatus Source

Show ThreadStatus

Since: base-4.3.0.0

Instance details

Defined in GHC.Conc.Sync

Methods

showsPrec :: Int -> ThreadStatus -> ShowS Source

show :: ThreadStatus -> String Source

showList :: [ThreadStatus] -> ShowS Source

data BlockReason Source

Краткое описание конструкторов

BlockedOnMVar

заблокирован на MVar

BlockedOnBlackHole

заблокирован на вычислении, выполняемом другим потоком

BlockedOnException

заблокирован в throwTo

BlockedOnSTM

заблокирован в retry в транзакции STM

BlockedOnForeignCall

в данный момент выполняется внешний вызов

BlockedOnOther

заблокирован на каком-то другом ресурсе. Без -threaded, ввод-вывод и threadDelay отображаются как BlockedOnOther, с -threaded они отображаются как BlockedOnMVar.

Примеры использования
Подробности примеров
Eq BlockReason

С момента: base-4.3.0.0

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

Определено в GHC.Conc.Sync

Методы

(==) :: BlockReason -> BlockReason -> Bool Исходный код

(/=) :: BlockReason -> BlockReason -> Bool Исходный код

Ord BlockReason

С момента: base-4.3.0.0

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

Определено в GHC.Conc.Sync

Методы

compare :: BlockReason -> BlockReason -> Ordering Исходный код

(<) :: BlockReason -> BlockReason -> Bool Исходный код

(<=) :: BlockReason -> BlockReason -> Bool Исходный код

(>) :: BlockReason -> BlockReason -> Bool Исходный код

(>=) :: BlockReason -> BlockReason -> Bool Исходный код

max :: BlockReason -> BlockReason -> BlockReason Исходный код

min :: BlockReason -> BlockReason -> BlockReason Исходный код

Show BlockReason

С момента: base-4.3.0.0

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

Определено в GHC.Conc.Sync

Методы

showsPrec :: Int -> BlockReason -> ShowS Исходный код

show :: BlockReason -> Строка Исходный код

showList :: [BlockReason] -> ShowS Исходный код

threadStatus :: ThreadId -> IO ThreadStatus Исходный код

threadCapability :: ThreadId -> IO (Целое число, Булево значение) Исходный код

Возвращает номер ресурса, на котором в данный момент выполняется поток, и булево значение, указывающее, заблокирован ли поток к этому ресурсу. Поток заблокирован к ресурсу, если он был создан с помощью forkOn.

С момента: base-4.4.0.0

newStablePtrPrimMVar :: MVar () -> IO (StablePtr PrimMVar) Исходный код

Создаёт StablePtr, который можно передать в функцию C hs_try_putmvar(). RTS требует StablePtr к базовому MVar#, но StablePtr# может ссылаться только на повышенные типы, поэтому мы вынуждены обмануть, принудительно преобразуя типы.

data PrimMVar Исходный код

Счётчик и квота выделения памяти

setAllocationCounter :: Int64 -> IO () Исходный код

Каждый поток имеет счётчик выделения памяти, который отслеживает, сколько памяти было выделено потоком. Счётчик инициализируется нулём, и setAllocationCounter устанавливает текущее значение. Счётчик выделения памяти отсчитывается *вниз*, поэтому в отсутствие вызова setAllocationCounter его значение является отрицанием количества выделенных байтов памяти потоком.

С этим счётчиком можно сделать две вещи:

  • Использовать его как простой механизм профилирования с помощью getAllocationCounter.
  • Использовать его как ограничение ресурсов. См. enableAllocationLimit.

Отчёт о выделении памяти точен только примерно до 4 Кб.

С момента: base-4.8.0.0

getAllocationCounter :: IO Int64 Исходный код

Возвращает текущее значение счётчика выделения памяти для текущего потока.

С момента: base-4.8.0.0

enableAllocationLimit :: IO () Исходный код

Включает возможность использования счётчика выделения памяти в качестве ограничения для текущего потока. Когда ограничение выделения памяти включено, если счётчик выделения памяти упадёт ниже нуля, поток получит асинхронное исключение AllocationLimitExceeded. В этом случае счётчик сбрасывается (по умолчанию до 100 Кб, но настраиваемое с помощью параметра +RTS -xq), чтобы он мог обработать исключение и выполнить необходимые действия по очистке. Если он исчерпает это дополнительное разрешение, будет отправлено другое исключение AllocationLimitExceeded, и так далее. Как и другие асинхронные исключения, исключение AllocationLimitExceeded откладывается, пока поток находится внутри mask или обработчике исключений в catch.

Обратите внимание, что выделение памяти не связано с живой памятью, также известной как обитанием в куче. Поток может выделить большое количество памяти и сохранить от нуля до всего. Лучше думать об ограничении выделения как об ограничении времени работы ЦП, а не как об ограничении памяти.

По сравнению с использованием тайм-аутов, ограничения выделения памяти не учитывают время, потраченное на ожидание или выполнение внешних вызовов.

Since: base-4.8.0.0

disableAllocationLimit :: IO () Source

Отключить обработку лимита выделения памяти для текущего потока.

Since: base-4.8.0.0

TVars

newtype STM a Source

Монад, поддерживающий атомарные транзакции памяти.

Конструкторы

STM (State# RealWorld -> (# State# RealWorld, a #))
Экземпляры
Подробности о экземплярах
Monad STM

Since: base-4.3.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

(>>=) :: STM a -> (a -> STM b) -> STM b Source

(>>) :: STM a -> STM b -> STM b Source

return :: a -> STM a Source

Functor STM

Since: base-4.3.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

fmap :: (a -> b) -> STM a -> STM b Source

(<$) :: a -> STM b -> STM a Source

Applicative STM

Since: base-4.8.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

pure :: a -> STM a Source

(<*>) :: STM (a -> b) -> STM a -> STM b Source

liftA2 :: (a -> b -> c) -> STM a -> STM b -> STM c Source

(*>) :: STM a -> STM b -> STM b Source

(<*) :: STM a -> STM b -> STM a Source

MonadPlus STM

Since: base-4.3.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

mzero :: STM a Source

mplus :: STM a -> STM a -> STM a Source

Alternative STM

Since: base-4.8.0.0

Подробности о экземпляре

Определено в GHC.Conc.Sync

Методы

empty :: STM a Source

(<|>) :: STM a -> STM a -> STM a Source

some :: STM a -> STM [a] Source

many :: STM a -> STM [a] Source

atomically :: STM a -> IO a Source

Выполнить серию действий STM атомарно.

Использование atomically внутри unsafePerformIO или unsafeInterleaveIO подрывает некоторые гарантии, предоставляемые STM. Это позволяет запускать транзакцию внутри другой транзакции, в зависимости от того, когда вычисляется thunk. Если попытка вложенной транзакции предпринята, средой выполнения выбрасывается исключение. Можно безопасно использовать atomically внутри unsafePerformIO или unsafeInterleaveIO, но система типов не исключает программы, которые могут пытаться выполнить вложенные транзакции, а это значит, что программист должен проявлять особую осторожность, чтобы предотвратить это.

Однако существуют функции для создания транзакционных переменных, которые всегда можно безопасно вызывать в unsafePerformIO. Смотрите: newTVarIO, newTChanIO, newBroadcastTChanIO, newTQueueIO, newTBQueueIO, и newTMVarIO.

Использование unsafePerformIO внутри atomically также опасно, но по другим причинам. Смотрите unsafeIOToSTM для получения дополнительной информации.

retry :: STM a Source

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

orElse :: STM a -> STM a -> STM a Source

Составление двух альтернативных действий STM (только GHC).

Если первое действие завершается без повторной попытки, то оно формирует результат orElse. В противном случае, если первое действие повторяется, то вместо него выполняется второе действие. Если оба действия повторяются, то orElse в целом повторяется.

throwSTM :: Exception e => e -> STM a Source

Вариант throw, который можно использовать только внутри монады STM.

Выброс исключения в STM прерывает транзакцию и распространяет исключение. Если исключение перехвачено через catchSTM, только изменения, заключенные в блок catch, отменяются; изменения, сделанные за пределами catchSTM, сохраняются.

Если исключение не перехвачено внутри STM, оно повторно выбрасывается atomically, и вся транзакция STM отменяется.

Хотя throwSTM имеет тип, являющийся экземпляром типа throw, эти две функции немного отличаются:

throw e    `seq` x  ===> throw e
throwSTM e `seq` x  ===> x

Первый пример вызовет поднятие исключения e, а второй — нет. Фактически, throwSTM будет вызывать исключение только при использовании внутри монады STM. Следует использовать вариант throwSTM вместо throw для поднятия исключения внутри монады STM, поскольку он гарантирует порядок относительно других операций STM, тогда как throw этого не гарантирует.

catchSTM :: Exception e => STM a -> (e -> STM a) -> STM a Source

Обработка исключений внутри действий STM.

catchSTM m f перехватывает любое исключение, выброшенное m с помощью throwSTM, используя функцию f для обработки исключения. Если исключение выброшено, все изменения, внесённые m, отменяются, но изменения, внесённые до m, сохраняются.

data TVar a Source

Локальные места памяти с поддержкой атомных операций транзакции.

Конструкторы

TVar (TVar# RealWorld a)
Экземпляры
Подробности экземпляров
Eq (TVar a)

Since: base-4.8.0.0

Подробности экземпляра

Определено в GHC.Conc.Sync

Методы

(==) :: TVar a -> TVar a -> Bool Source

(/=) :: TVar a -> TVar a -> Bool Source

newTVar :: a -> STM (TVar a) Source

Создание нового TVar, содержащего предоставленное значение.

newTVarIO :: a -> IO (TVar a) Source

Вариант IO функции newTVar. Это полезно для создания глобальных TVar с использованием unsafePerformIO, поскольку использование atomically внутри unsafePerformIO невозможно.

readTVar :: TVar a -> STM a Source

Возвращает текущее значение, хранящееся в TVar.

readTVarIO :: TVar a -> IO a Source

Возвращает текущее значение, хранящееся в TVar. Это эквивалентно

 readTVarIO = atomically . readTVar

но работает намного быстрее, так как не выполняет полную транзакцию, а только считывает текущее значение TVar.

writeTVar :: TVar a -> a -> STM () Source

Записывает предоставленное значение в TVar.

unsafeIOToSTM :: IO a -> STM a Source

Небезопасно выполняет IO в монаде STM. Осторожно: это очень рискованно.

  • Реализация STM часто будет запускать транзакции несколько раз, поэтому необходимо быть готовым к этому, если ваш IO имеет побочные эффекты.
  • Реализация STM будет прерывать транзакции, которые, как известно, недействительны и требуют перезапуска. Это может произойти в середине unsafeIOToSTM, поэтому убедитесь, что не получаете ресурсы, которые нужно освобождать (обработчики исключений игнорируются при прерывании транзакции). Это включает выполнение любого ввода-вывода с использованием дескрипторов, например. Неправильное выполнение этого, вероятно, приведёт к случайным тупикам.
  • Транзакция может видеть несогласованное представление памяти во время выполнения IO. Инварианты, которые вы ожидаете в вашей программе, могут не выполняться внутри транзакции из-за способа реализации транзакций. Обычно это не видно программисту, но использование unsafeIOToSTM может его раскрыть.

Разное

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

Обеспечивает выполнение действия с текущим значением MVar. MVar будет пустым в течение времени выполнения действия.

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

Изменение значения MVar.

setUncaughtExceptionHandler :: (SomeException -> IO ()) -> IO () Source

getUncaughtExceptionHandler :: IO (SomeException -> IO ()) Source

reportError :: SomeException -> IO () Source

reportStackOverflow :: IO () Source

reportHeapOverflow :: IO () Source

sharedCAF :: a -> (Ptr a -> IO (Ptr a)) -> IO a Source

© 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/GHC-Conc-Sync.html

Spec-Zone.ru

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