GHC.Conc.Sync
| Авторские права | (c) The University of Glasgow 1994-2002 |
|---|---|
| Лицензия | см. libraries/base/LICENSE |
| Сопровождающие | ghc-devs@haskell.org |
| Стабильность | внутренний |
| Переносимость | непереносимый (расширения GHC) |
| Безопасный Haskell | Нет |
| Язык | Haskell2010 |
Описание
Основные средства для работы с параллелизмом.
Потоки
data ThreadId Исходный код
ThreadId — это абстрактный тип, представляющий дескриптор потока. ThreadId является экземпляром Eq, Ord и Show, причём экземпляр Ord реализует произвольный полный порядок для ThreadId. Экземпляр Show позволяет преобразовать ThreadId с произвольным значением в строку; вывод значения ThreadId иногда бывает полезен при отладке или диагностике поведения параллельной программы.
Примечание: в GHC, если у вас есть ThreadId, то, по сути, у вас есть указатель непосредственно на поток. Это означает, что сам поток нельзя будет собрать сборщиком мусора, пока вы не освободите ThreadId. Эту нежелательную особенность было бы сложно исправить, продолжая поддерживать threadStatus.
Экземпляры
| Eq ThreadId Исходный код | Начиная с: base-4.2.0.0 |
Определён в GHC.Internal.Conc.Sync Методы(==) :: ThreadId -> ThreadId -> Bool Исходный код (/=) :: ThreadId -> ThreadId -> Bool Исходный код | |
| Ord ThreadId Исходный код | Начиная с: base-4.2.0.0 |
Определён в GHC.Internal.Conc.Sync Методыcompare :: ThreadId -> ThreadId -> Ordering Исходный код (<) :: ThreadId -> ThreadId -> Bool Исходный код (<=) :: ThreadId -> ThreadId -> Bool Исходный код (>) :: ThreadId -> ThreadId -> Bool Исходный код (>=) :: ThreadId -> ThreadId -> Bool Исходный код max :: ThreadId -> ThreadId -> ThreadId Исходный код min :: ThreadId -> ThreadId -> ThreadId Исходный код | |
| Show ThreadId Исходный код | Начиная с: base-4.2.0.0 |
Определён в GHC.Internal.Conc.Sync МетодыshowsPrec :: Int -> ThreadId -> ShowS Исходный код show :: ThreadId -> String Исходный код showList :: [ThreadId] -> ShowS Исходный код | |
fromThreadId :: ThreadId -> Word64 Исходный код
Сопоставляет потоку целочисленный идентификатор, уникальный в пределах текущего процесса.
Начиная с: base-4.19.0.0
showThreadId :: ThreadId -> String Исходный код
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 отличается от описанного в статье «Asynchronous exceptions in 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.
yield :: IO () Исходный код
Действие yield позволяет (а при кооперативной многозадачности — принудительно вызывает) переключиться на любой другой поток, готовый к выполнению в данный момент (если таковой имеется), и иногда бывает полезно при реализации абстракций параллелизма.
labelThread :: ThreadId -> String -> IO () Исходный код
labelThread сохраняет строку как идентификатор этого потока. Этот идентификатор будет использоваться в отладочных сообщениях, чтобы упростить различение потоков (иначе доступен только адрес объекта состояния потока в куче). Также в журнал событий RTS записывается событие.
labelThreadByteArray# :: ThreadId -> ByteArray# -> IO () Исходный код
labelThreadByteArray# задаёт метку потока в виде указанной строки в кодировке UTF-8, содержащейся в ByteArray#.
Начиная с: base-4.18
mkWeakThreadId :: ThreadId -> IO (Weak ThreadId) Исходный код
Создаёт слабый указатель на ThreadId. Это может быть важно, если необходимо хранить ссылку на ThreadId, позволяя при этом потоку получать исключения семейства BlockedIndefinitely (например, BlockedIndefinitelyOnMVar). Обычная ссылка на ThreadId предотвратит доставку исключений BlockedIndefinitely, поскольку эту ссылку в любой момент можно использовать как цель для throwTo, что разблокирует поток.
С другой стороны, хранение Weak ThreadId не помешает потоку получать исключения BlockedIndefinitely. Исключение по-прежнему можно отправить в Weak ThreadId, но вызывающий код должен сначала использовать deRefWeak, чтобы определить, существует ли ещё поток.
Начиная с: base-4.6.0.0
Запросы
listThreads :: IO [ThreadId] Исходный код
Возвращает список потоков Haskell текущего процесса.
Начиная с: base-4.18
threadLabel :: ThreadId -> IO (Maybe String) Исходный код
Запрашивает метку потока; возвращает Nothing, если метка потока не была задана.
Начиная с: base-4.18
data ThreadStatus Исходный код
Текущее состояние потока
Конструкторы
| ThreadRunning | поток готов к выполнению или выполняется в данный момент |
| ThreadFinished | поток завершил работу |
| ThreadBlocked BlockReason | поток заблокирован в ожидании какого-либо ресурса |
| ThreadDied | поток получил необработанное исключение |
Экземпляры
| Eq ThreadStatus Исходный код | Начиная с: base-4.3.0.0 |
Определён в GHC.Internal.Conc.Sync Методы(==) :: ThreadStatus -> ThreadStatus -> Bool Исходный код (/=) :: ThreadStatus -> ThreadStatus -> Bool Исходный код | |
| Ord ThreadStatus Исходный код | Начиная с: base-4.3.0.0 |
Определён в GHC.Internal.Conc.Sync Методыcompare :: ThreadStatus -> ThreadStatus -> Ordering Исходный код (<) :: ThreadStatus -> ThreadStatus -> Bool Исходный код (<=) :: ThreadStatus -> ThreadStatus -> Bool Исходный код (>) :: ThreadStatus -> ThreadStatus -> Bool Исходный код (>=) :: ThreadStatus -> ThreadStatus -> Bool Исходный код max :: ThreadStatus -> ThreadStatus -> ThreadStatus Исходный код min :: ThreadStatus -> ThreadStatus -> ThreadStatus Исходный код | |
| Show ThreadStatus Исходный код | Начиная с: base-4.3.0.0 |
Определён в GHC.Internal.Conc.Sync МетодыshowsPrec :: Int -> ThreadStatus -> ShowS Исходный код show :: ThreadStatus -> String Исходный код showList :: [ThreadStatus] -> ShowS Исходный код | |
data BlockReason Исходный код
Конструкторы
| BlockedOnMVar | заблокирован в ожидании |
| BlockedOnBlackHole | заблокирован в ожидании вычисления, выполняемого другим потоком |
| BlockedOnException | заблокирован внутри |
| BlockedOnSTM | заблокирован внутри |
| BlockedOnForeignCall | в данный момент выполняет внешний вызов |
| BlockedOnOther | заблокирован в ожидании другого ресурса. Без |
Экземпляры
| Eq BlockReason Источник | С версии: base-4.3.0.0 |
Определено в GHC.Internal.Conc.Sync Методы(==) :: BlockReason -> BlockReason -> Bool Источник (/=) :: BlockReason -> BlockReason -> Bool Источник | |
| Ord BlockReason Источник | С версии: base-4.3.0.0 |
Определено в GHC.Internal.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.Internal.Conc.Sync МетодыshowsPrec :: Int -> BlockReason -> ShowS Источник show :: BlockReason -> String Источник showList :: [BlockReason] -> ShowS Источник | |
threadStatus :: ThreadId -> IO ThreadStatus Источник
Запрашивает текущее состояние выполнения потока.
threadCapability :: ThreadId -> IO (Int, Bool) Источник
Возвращает номер возможности, на которой в данный момент выполняется поток, и логическое значение, указывающее, привязан ли поток к этой возможности. Поток привязан к возможности, если он был создан с помощью forkOn.
С версии: base-4.4.0.0
Создание потоков и прочее
forkIO :: IO () -> IO ThreadId Источник
Создаёт новый поток для выполнения вычисления IO, переданного в качестве первого аргумента, и возвращает ThreadId созданного потока.
Новый поток будет лёгким, непривязанным потоком. Вызовы внешних функций из этого потока не гарантированно выполняются каким-либо конкретным потоком ОС; если необходимо, чтобы внешние вызовы выполнялись определённым потоком ОС, используйте forkOS.
Новый поток наследует маскированное состояние родительского потока (см. mask).
У созданного потока есть обработчик исключений, который отбрасывает исключения BlockedIndefinitelyOnMVar, BlockedIndefinitelyOnSTM и ThreadKilled, а все остальные исключения передаёт обработчику неперехваченных исключений.
ПРЕДУПРЕЖДЕНИЕ: Исключения в новом потоке не будут повторно выброшены в потоке, который его создал. Это означает, что вы можете совершенно не знать о проблеме, если она возникнет. Вместо этого можно использовать библиотеку async.
forkIOWithUnmask :: ((forall a. IO a -> IO a) -> IO ()) -> IO ThreadId Источник
Как forkIO, но дочернему потоку передаётся функция, с помощью которой можно снять маску с асинхронных исключений. Обычно эту функцию используют следующим образом
... mask_ $ forkIOWithUnmask $ \unmask ->
catch (unmask ...) handler
чтобы обработчик исключений в дочернем потоке устанавливался при замаскированных асинхронных исключениях, а основное тело дочернего потока выполнялось без маски.
Обратите внимание: функция снятия маски, переданная дочернему потоку, должна использоваться только в этом потоке; поведение не определено, если вызвать её в другом потоке.
С версии: base-4.4.0.0
forkOn :: Int -> IO () -> IO ThreadId Источник
Как 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
Искры
Возвращает число искр, находящихся в данный момент в локальном пуле искр
childHandler :: SomeException -> IO () Источник
par :: a -> b -> b infixr 0 Источник
pseq :: a -> b -> b infixr 0 Источник
Внутренняя функция, используемая RTS для выполнения искр.
PrimMVar
newStablePtrPrimMVar :: MVar a -> IO (StablePtr PrimMVar) Источник
Создаёт StablePtr, который можно передать функции C hs_try_putmvar(). RTS требуется StablePtr для нижележащего MVar#, однако StablePtr# может ссылаться только на типы с поднятым значением, поэтому приходится прибегать к хитрости с приведением типов.
Счётчик выделения памяти и квота
setAllocationCounter :: Int64 -> IO () Источник
У каждого потока есть счётчик выделения памяти, который отслеживает, сколько памяти выделил этот поток. Счётчик инициализируется нулём, а setAllocationCounter задаёт его текущее значение. Счётчик выделения памяти ведёт обратный отсчёт, поэтому, если не вызывать setAllocationCounter, его значение равно отрицательному числу байтов памяти, выделенной потоком.
Этот счётчик можно использовать двумя способами:
- В качестве простого механизма профилирования с помощью
getAllocationCounter. - В качестве ограничения ресурсов. См.
enableAllocationLimit.
Учёт выделения памяти точен лишь примерно до 4 Кбайт.
С версии: base-4.8.0.0
getAllocationCounter :: IO Int64 Источник
Возвращает текущее значение счётчика выделения памяти для текущего потока.
С версии: base-4.8.0.0
enableAllocationLimit :: IO () Источник
Включает использование счётчика выделения памяти в качестве ограничения для текущего потока. Если ограничение выделения памяти включено и значение счётчика становится меньше нуля, потоку отправляется асинхронное исключение AllocationLimitExceeded. При этом счётчик инициализируется заново (по умолчанию значением 100K, которое можно настроить с помощью параметра +RTS -xq), чтобы обработать исключение и выполнить необходимую очистку. Если поток исчерпает и эту дополнительную квоту, будет отправлено ещё одно исключение AllocationLimitExceeded и так далее. Как и другие асинхронные исключения, исключение AllocationLimitExceeded откладывается, пока поток находится внутри mask или обработчика исключений в catch.
Обратите внимание, что выделение памяти не связано с живой памятью, также известной как занятый объём кучи. Поток может выделить большой объём памяти и сохранить от нуля до всего этого объёма. Ограничение выделения памяти следует воспринимать скорее как ограничение времени ЦП, а не как ограничение объёма памяти.
В отличие от тайм-аутов, ограничения выделения памяти не учитывают время, проведённое в ожидании или во внешних вызовах.
С версии: base-4.8.0.0
disableAllocationLimit :: IO () Источник
Отключает обработку ограничения выделения памяти для текущего потока.
С версии: base-4.8.0.0
TVars
Монада, поддерживающая атомарные транзакции с памятью.
Экземпляры
atomically :: STM a -> IO a Исходный код
Атомарно выполняет последовательность действий STM.
Использование atomically внутри unsafePerformIO или unsafeInterleaveIO нарушает некоторые гарантии, предоставляемые STM. Это позволяет выполнять транзакцию внутри другой транзакции в зависимости от того, когда вычисляется thunk. При попытке вложенной транзакции среда выполнения выбрасывает исключение. Можно безопасно использовать atomically внутри unsafePerformIO или unsafeInterleaveIO, но проверка типов не исключает программы, которые могут пытаться выполнять вложенные транзакции, поэтому программисту необходимо принять особые меры, чтобы этого не допустить.
Однако существуют функции для создания транзакционных переменных, которые всегда можно безопасно вызывать в unsafePerformIO. См.: newTVarIO, newTChanIO, newBroadcastTChanIO, newTQueueIO, newTBQueueIO и newTMVarIO.
Использование unsafePerformIO внутри atomically также опасно, но по другим причинам. Подробнее см. unsafeIOToSTM.
retry :: STM a Исходный код
Повторяет выполнение текущей транзакции с памятью, поскольку она прочитала значения в TVars, указывающие на то, что выполнение не следует продолжать (например, TVars представляют общий буфер, который теперь пуст). Реализация может заблокировать поток до тех пор, пока одна из TVars, из которых были прочитаны значения, не будет обновлена. (Только GHC)
orElse :: STM a -> STM a -> STM a Исходный код
Объединяет два альтернативных действия STM (только GHC).
Если первое действие завершается без повтора, оно становится результатом orElse. В противном случае, если первое действие повторяется, вместо него выполняется второе. Если оба действия повторяются, то orElse целиком повторяется.
throwSTM :: Exception e => e -> STM a Исходный код
Вариант throw, который можно использовать только в монаде STM.
Выбрасывание исключения в STM прерывает транзакцию и передаёт исключение дальше. Если исключение перехватывается с помощью catchSTM, отменяются только изменения, заключённые в блок перехвата; изменения, сделанные вне catchSTM, сохраняются.
Если исключение не перехвачено внутри STM, оно повторно выбрасывается функцией atomically, и вся STM отменяется.
Хотя throwSTM имеет тип, являющийся экземпляром типа throw, эти две функции несколько различаются:
throw e `seq` x ===> throw e throwSTM e `seq` x ===> x
В первом примере будет выброшено исключение e, а во втором — нет. Фактически throwSTM выбрасывает исключение только при использовании внутри монады STM. Для выбрасывания исключения внутри монады STM предпочтительно использовать вариант throwSTM, а не throw, поскольку он гарантирует упорядочение относительно других операций STM, тогда как throw такой гарантии не даёт.
catchSTM :: Exception e => STM a -> (e -> STM a) -> STM a Исходный код
Обработка исключений в действиях STM.
catchSTM m f перехватывает любое исключение, выброшенное m с помощью throwSTM, и передаёт его для обработки функции f. Если выброшено исключение, все изменения, сделанные m, отменяются, но изменения, сделанные до m, сохраняются.
data TVar a Исходный код
Общие области памяти, поддерживающие атомарные транзакции с памятью.
Экземпляры
| Eq (TVar a) Исходный код | С версии: base-4.8.0.0 |
Определено в GHC.Internal.Conc.Sync | |
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 Исходный код
Выполняет действие IO с текущим значением MVar. На время выполнения действия MVar будет пустой.
modifyMVar_ :: MVar a -> (a -> IO a) -> IO () Исходный код
Изменяет значение MVar.
setUncaughtExceptionHandler :: (SomeException -> IO ()) -> IO () Исходный код
getUncaughtExceptionHandler :: IO (SomeException -> IO ()) Исходный код
reportError :: SomeException -> IO () Исходный код
reportStackOverflow :: IO () Исходный код
reportHeapOverflow :: IO () Исходный код
sharedCAF :: a -> (Ptr a -> IO (Ptr a)) -> IO a Исходный код
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/9.14.1/docs/libraries/base-4.22.0.0-66f8/GHC-Conc-Sync.html