GHC.Conc
| Авторские права | (c) Университет Глазго, 1994-2002 |
|---|---|
| Лицензия | см. libraries/base/LICENSE |
| Поддержка | cvs-ghc@haskell.org |
| Устойчивость | внутренняя |
| Переносимость | непереносимая (расширения GHC) |
| Безопасный Haskell | Небезопасный |
| Язык | Haskell2010 |
Содержание
Описание
Базовые средства для конкурентного программирования.
Тип ThreadId — это абстрактный тип, представляющий дескриптор потока. ThreadId является экземпляром Eq, Ord и Show, где экземпляр Ord реализует произвочный тотальный порядок для ThreadId. Экземпляр Show позволяет преобразовать ThreadId произвольного значения в строковое представление; показ значения ThreadId иногда бывает полезен при отладке или диагностике поведения конкуретной программы.
Примечание: в GHC, если у вас есть ThreadId, вы фактически имеете указатель на сам поток. Это означает, что сам поток не может быть удалён сборщиком мусора, пока вы не удалите ThreadId. Эта особенность, вероятно, будет исправлена в будущем.
Разделение потоков и аналогичные операции
forkIO :: IO () -> IO ThreadId Источник
Создаёт новый поток для выполнения переданного в качестве первого аргумента вычисления IO и возвращает идентификатор ThreadId вновь созданного потока.
Новый поток будет лёгким, непривязанным потоком. Внешние вызовы, выполняемые этим потоком, не гарантируются к выполнению в конкретном потоке ОС; если вам нужны внешние вызовы в определённом потоке ОС, используйте forkOS.
Новый поток наследует маскированное состояние родительского потока (см. mask).
У вновь созданного потока есть обработчик исключений, который игнорирует исключения BlockedIndefinitelyOnMVar, BlockedIndefinitelyOnSTM и ThreadKilled, и передаёт все остальные исключения обработчику необработанных исключений.
forkIOWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId Источник
Аналогично forkIO, но дочерний поток получает функцию, которая может использоваться для отключения асинхронных исключений. Эта функция обычно используется следующим образом
... mask_ $ forkIOWithUnmask $ \unmask ->
catch (unmask ...) handler
чтобы обработчик исключений в дочернем потоке был установлен с асинхронными исключениями, замаскированными, в то время как основная часть дочернего потока выполняется в размаскированном состоянии.
Обратите внимание, что функция размаскирования, переданная дочернему потоку, должна использоваться только в этом потоке; поведение не определено, если она вызывается в другом потоке.
С версии: 4.4.0.0
forkOn :: Int -> IO () -> IO ThreadId Источник
Аналогично forkIO, но позволяет указать, на какой возможности должен работать поток. В отличие от forkIO потока, поток, созданный с помощью forkOn, будет оставаться на той же возможности на протяжении всего своего жизненного цикла (forkIO потоки могут мигрировать между возможностями в соответствии с политикой планирования). forkOn полезна для переопределения политики планирования, когда заранее известно, как лучше распределить потоки.
Аргумент Int задаёт номер возможности (см. getNumCapabilities). Обычно возможности соответствуют физическим процессорам, но точное поведение зависит от реализации. Значение, переданное forkOn, интерпретируется по модулю общего числа возможностей, как возвращает getNumCapabilities.
Примечание GHC: число возможностей задаётся параметром +RTS -N при запуске программы. Возможности могут быть привязаны к физическим ядрам процессора с помощью +RTS -qa, если это поддерживает операционная система, хотя на практике это обычно не требуется (и может даже снизить производительность в некоторых случаях — рекомендуется экспериментирование).
С версии: 4.4.0.0
forkOnWithUnmask :: Int -> ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId Источник
Аналогично forkIOWithUnmask, но дочерний поток привязан к указанному процессору, как и при использовании forkOn.
С версии: 4.4.0.0
numCapabilities :: Int Источник
значение, переданное флагу +RTS -N. Это число потоков Haskell, которые могут выполняться одновременно в любой момент времени, и обычно устанавливается равным числу физических ядер процессора в машине.
Строго говоря, лучше использовать getNumCapabilities, потому что число возможностей может изменяться во время выполнения.
getNumCapabilities :: IO Int Источник
Возвращает количество потоков Haskell, которые могут выполняться одновременно (на отдельных физических процессорах) в любой момент времени. Для изменения этого значения используйте setNumCapabilities.
С версии: 4.4.0.0
setNumCapabilities :: Int -> IO () Источник
Устанавливает количество потоков Haskell, которые могут выполняться одновременно (на отдельных физических процессорах) в любой момент времени. Число, переданное forkOn, интерпретируется по модулю этого значения. Начальное значение задаётся флагом времени выполнения +RTS -N.
Это также количество потоков, которые будут участвовать в параллельном сборке мусора. Сильно рекомендуется, чтобы число возможностей не превышало количество физических ядер процессора, и часто бывает полезно оставить одно или несколько ядер свободными, чтобы избежать конкуренции с другими процессами в машине.
С версии: 4.5.0.0
getNumProcessors :: IO Int Источник
Возвращает количество ЦП в машине
С версии: 4.5.0.0
Возвращает количество искр в локальном пуле искр.
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 () Source
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, за исключением того, что исключение выбрасывается как асинхронное исключение. Это означает, что если существует охватывающее чистое вычисление, что было бы в случае, если текущая операция ввода-вывода находится внутри unsafePerformIO или unsafeInterleaveIO, это вычисление не заменяется исключением навсегда, а приостанавливается так, как если бы оно получило асинхронное исключение.
Обратите внимание, что если throwTo вызывается с текущей нитью в качестве цели, исключение будет вызвано даже если нить в настоящее время находится внутри mask или uninterruptibleMask.
par :: a -> b -> b infixr 0 Source
pseq :: a -> b -> b infixr 0 Source
Внутренняя функция, используемая RTS для запуска искр.
Действие yield позволяет (принуждает в реализации кооперативного многозадачности) контекст-переключению на любую другую в настоящее время готовую нить (если таковые имеются) и иногда полезно при реализации абстракций параллельности.
labelThread :: ThreadId -> String -> IO () Source
labelThread сохраняет строку в качестве идентификатора для этой нити, если вы скомпилировали RTS с поддержкой отладки. Этот идентификатор будет использоваться в выходных данных отладки, чтобы облегчить различение различных нитей (в противном случае у вас будет только адрес объекта состояния нити в куче).
Другие приложения, такие как графический отладчик Concurrent Haskell (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: 4.6.0.0
data ThreadStatus Source
Текущее состояние нити
Конструкторы
| ThreadRunning | нить в настоящее время готова к выполнению или выполняется |
| ThreadFinished | нить завершена |
| ThreadBlocked BlockReason | нить заблокирована на некотором ресурсе |
| ThreadDied | нить получила необработанное исключение |
Примеры
data BlockReason Source
Конструкторы
| BlockedOnMVar | заблокирован на |
| BlockedOnBlackHole | заблокирован на вычислении, выполняемом другой нитью |
| BlockedOnException | заблокирован при |
| BlockedOnSTM | заблокирован в |
| BlockedOnForeignCall | в настоящее время выполняет вызов внешней функции |
| BlockedOnOther | заблокирован на другом ресурсе. Без |
Примеры
threadStatus :: ThreadId -> IO ThreadStatus Source
возвращает номер способности, на которой в данный момент выполняется поток, и булево значение, указывающее, заблокирован ли поток к этой способности. Поток заблокирован к способности, если он был создан с forkOn.
Since: 4.4.0.0
Ожидание
threadDelay :: Int -> IO () Source
Приостанавливает текущий поток на заданное количество микросекунд (только GHC).
Нет гарантии, что поток будет быстро запланирован заново, когда задержка истечёт, но поток никогда не возобновит выполнение раньше, чем указано.
registerDelay :: Int -> IO (TVar Bool) Source
Устанавливает значение возвращённого TVar в True после заданного количества микросекунд. Также применимы замечания, связанные с threadDelay.
threadWaitRead :: Fd -> IO () Source
Заблокирует текущий поток, пока данные не станут доступны для чтения в заданном дескрипторе файла (только GHC).
Это выбросит IOError, если дескриптор файла был закрыт, в то время как этот поток был заблокирован. Чтобы безопасно закрыть дескриптор файла, который был использован с threadWaitRead, используйте closeFdWith.
threadWaitWrite :: Fd -> IO () Source
Заблокирует текущий поток, пока данные не будут готовы для записи в заданный дескриптор файла (только GHC).
Это выбросит IOError, если дескриптор файла был закрыт, в то время как этот поток был заблокирован. Чтобы безопасно закрыть дескриптор файла, который был использован с threadWaitWrite, используйте closeFdWith.
threadWaitReadSTM :: Fd -> IO (STM (), IO ()) Source
Возвращает действие STM, которое можно использовать для ожидания данных для чтения из дескриптора файла. Второе возвращаемое значение - это действие IO, которое можно использовать для отмены интереса к дескриптору файла.
threadWaitWriteSTM :: Fd -> IO (STM (), IO ()) Source
Возвращает действие STM, которое можно использовать для ожидания, пока данные не будут доступны для записи в дескриптор файла. Второе возвращаемое значение - это действие IO, которое можно использовать для отмены интереса к дескриптору файла.
Аргументы
| :: (Fd -> IO ()) | Действие низкого уровня, которое выполняет фактическое закрытие. |
| -> Fd | Дескриптор файла для закрытия. |
| -> IO () |
Закрывает дескриптор файла безопасным для конкурентного доступа способом (только GHC). Если вы используете threadWaitRead или threadWaitWrite для выполнения блокирующего ввода-вывода, вы обязаны использовать эту функцию для закрытия дескрипторов файлов, иначе заблокированные потоки могут не быть разблокированы.
Любые потоки, которые заблокированы на дескрипторе файла через threadWaitRead или threadWaitWrite, будут разблокированы путём выброса исключений IO.
Счётчик и лимит выделения памяти
setAllocationCounter :: Int64 -> IO () Source
Каждый поток имеет счётчик выделения, который отслеживает объём памяти, выделенный потоком. Счётчик инициализируется нулём, а setAllocationCounter устанавливает текущее значение. Счётчик выделения уменьшается, поэтому в отсутствие вызова setAllocationCounter его значение является отрицанием числа байт выделенной памяти потоком.
Есть две вещи, которые вы можете сделать с этим счётчиком:
- Использовать его в качестве простого механизма профилирования, с
getAllocationCounter. - Использовать его как лимит ресурса. См.
enableAllocationLimit.
Отслеживание выделения памяти точно только до примерно 4 Кбайт.
Since: 4.8.0.0
getAllocationCounter :: IO Int64 Source
Возвращает текущее значение счётчика выделения для текущего потока.
Since: 4.8.0.0
enableAllocationLimit :: IO () Source
Включает счётчик выделения, чтобы он обрабатывался как лимит для текущего потока. Когда лимит выделения включён, если счётчик выделения уменьшится ниже нуля, поток получит асинхронное исключение AllocationLimitExceeded. В этом случае счётчик сбрасывается (по умолчанию до 100К, но настраиваемый с помощью параметра +RTS -xq), чтобы он мог обработать исключение и выполнить необходимые операции по очистке. Если он исчерпает этот дополнительный лимит, будет выброшено ещё одно исключение AllocationLimitExceeded, и так далее.
Обратите внимание, что выделение памяти не связано с актуальной памятью, также известной как обитаемость кучи. Поток может выделить большое количество памяти и сохранить от нуля до всего из этого. Лучше рассматривать лимит выделения как ограничение по времени выполнения, а не по памяти.
В отличие от таймаутов, лимиты выделения не учитывают время, потраченное на ожидание или во время внешних вызовов.
Since: 4.8.0.0
disableAllocationLimit :: IO () Source
Отключает обработку лимита выделения для текущего потока.
Since: 4.8.0.0
TVars
Монад, поддерживающая атомные транзакции памяти.
Экземпляры
atomically :: STM a -> IO a Source
Выполняет серию действий STM атомарно.
Вы не можете использовать atomically внутри unsafePerformIO или unsafeInterleaveIO. Любая попытка сделать это приведёт к ошибке во время выполнения. (Причина: это фактически позволило бы транзакции внутри транзакции, в зависимости от того, когда именно вычисляется лямбда-выражение.)
Однако, см. newTVarIO, которое может вызываться внутри unsafePerformIO, и которое позволяет выделять TVars верхнего уровня.
Повторяет выполнение текущей транзакции памяти, потому что она увидела значения в TVars, которые означают, что она не должна продолжать (например, TVars представляют общий буфер, который теперь пуст). Реализация может заблокировать поток, пока один из TVars, из которого она считывала, не будет обновлён. (Только GHC)
Составьте два альтернативных действия STM (только GHC). Если первое действие завершается без повторных попыток, то оно формирует результат orElse. В противном случае, если первое действие повторяется, то вместо него выполняется второе действие. Если оба действия повторяются, то orElse в целом повторяется.
throwSTM :: Исключение e => e -> STM a Исходный код
Вариант throw, который может использоваться только в STM монаде.
Выбрасывание исключения в STM прерывает транзакцию и распространяет исключение.
Хотя throwSTM имеет тип, являющийся экземпляром типа throw, две функции немного различаются:
throw e `seq` x ===> throw e throwSTM e `seq` x ===> x
В первом примере будет вызвано исключение e, а во втором — нет. Фактически, throwSTM будет вызывать исключение только при использовании в STM монаде. Вариант throwSTM следует использовать вместо throw для повышения исключения в STM монаде, потому что он гарантирует порядок относительно других STM операций, тогда как throw этого не делает.
catchSTM :: Исключение e => STM a -> (e -> STM a) -> STM a Исходный код
Обработка исключений в действиях STM.
alwaysSucceeds :: STM a -> STM () Исходный код
alwaysSucceeds добавляет новое инвариантное свойство, которое должно быть истинным при передаче в alwaysSucceeds в конце текущей транзакции и в конце каждой последующей транзакции. Если оно нарушается в любой из этих точек, то нарушающая транзакция прерывается, и исключение, поднятое инвариантом, распространяется.
always :: STM Bool -> STM () Исходный код
always — это вариант alwaysSucceeds, в котором инвариант выражается как действие STM типа Bool, которое должно возвращать True. Возвращение False или выброс исключения также рассматриваются как нарушения инварианта.
data TVar a Исходный код
Объекты общей памяти, поддерживающие атомарные транзакции памяти.
newTVar :: a -> STM (TVar a) Исходный код
Создание нового TVar, содержащего предоставленное значение
newTVarIO :: a -> IO (TVar a) Исходный код
IO версия newTVar. Это полезно для создания основных TVar с использованием unsafePerformIO, поскольку использование atomically внутри unsafePerformIO невозможно.
readTVar :: TVar a -> STM a Исходный код
Возвращает текущее значение, хранящееся в TVar
readTVarIO :: TVar a -> IO a Исходный код
Возвращает текущее значение, хранящееся в TVar. Это эквивалентно
readTVarIO = atomically . readTVar
но работает намного быстрее, потому что не выполняет полную транзакцию, а только считывает текущее значение TVar.
writeTVar :: TVar a -> a -> STM () Исходный код
Записать предоставленное значение в TVar
unsafeIOToSTM :: IO a -> STM a Исходный код
Небезопасно выполняет IO в монаде STM. Осторожно: это очень опасно.
- Реализация STM часто выполняет транзакции несколько раз, поэтому вам необходимо быть готовым к этому, если ваш IO имеет побочные эффекты.
- Реализация STM прерывает транзакции, которые, как известно, являются недействительными и требуют перезапуска. Это может произойти в середине
unsafeIOToSTM, поэтому убедитесь, что вы не приобретаете ресурсы, которые необходимо высвободить (обработчики исключений игнорируются при прерывании транзакции). Это включает выполнение любого IO с использованием дескрипторов файлов, например. Если вы это сделаете неправильно, это, вероятно, приведёт к случайным тупикам. - Транзакция может увидеть несогласованный вид памяти, когда выполняется IO. Инварианты, которые вы ожидаете, будут истинными на протяжении всего вашего приложения, могут не быть истинными внутри транзакции из-за того, как реализованы транзакции. Обычно это не видно программисту, но использование
unsafeIOToSTMможет это раскрыть.
Разное
withMVar :: MVar a -> (a -> IO b) -> IO b Исходный код
type Сигнал = CInt Исходный код
type ФункцияОбработчика = ForeignPtr Word8 -> IO () Исходный код
setHandler :: Сигнал -> Может (ФункцияОбработчика, Динамический) -> IO (Может (ФункцияОбработчика, Динамический)) Исходный код
runHandlers :: ForeignPtr Word8 -> Сигнал -> IO () Исходный код
ensureIOManagerIsRunning :: IO () Исходный код
ioManagerCapabilitiesChanged :: IO () Исходный код
setUncaughtExceptionHandler :: (НекоторыеИсключения -> IO ()) -> IO () Исходный код
getUncaughtExceptionHandler :: IO (НекоторыеИсключения -> IO ()) Исходный код
reportError :: НекоторыеИсключения -> IO () Исходный код
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/7.10.3/docs/html/libraries/base-4.8.2.0/GHC-Conc.html