2013-07-06 4 views
10

Отказ от ответственности: Это можно легко сделать, используя MVar() в качестве простого мьютекса. Я просто любопытно посмотреть, можно ли это сделать с помощью STM.Можно ли это сделать с помощью STM?

Я хочу сделать следующее атомарно:

  • Прочитайте некоторые переменные.

  • Решите, какие операции ввода/вывода выполнять, исходя из того, что я только что прочитал.

  • Выполнение ввода-вывода.

  • Запишите результаты в переменных.

Для конкретности, предположим, что я хочу, чтобы отслеживать, сколько байтов ввода я прочитал, и делать вид, что я достиг EOF после того, как определенное количество байтов израсходованы. (ОК, позволяя двум потокам читать один и тот же файл одновременно, вероятно, является фальшивой вещью, чтобы сделать это в первую очередь, но пойдите со мной на этом ...)

Очевидно, что это не может быть одна транзакция STM; есть входы/выходы в середине. Очевидно, было бы также неправильно иметь это как две несвязанные транзакции. (Два потока могли видеть, что есть один байт квоты слева, и оба решили прочитать этот байт.)

Есть ли хорошее решение этой проблемы? Или STM просто неправильный инструмент для этой задачи?

+0

Это дает вам то, что вам нужно? «Парикмахер» может быть вашим указателем на чтение. http://stackoverflow.com/questions/16933678/are-tchan-writes-integrated-into-haskell-stm –

+0

@ DaxFohl Ну, вы _could_ используете STM для отправки всех запросов ввода-вывода в один поток через «TChan '... это должно сработать. – MathematicalOrchid

+0

Похоже, у вас есть стандартный прецедент для основного решения модели актера в стиле Эрланг, что и реализует вещи парикмахера через «STM» и «TChan». –

ответ

1

Я бы сказал, что STM не может этого сделать, и это специально. Часть кода STM может быть перезапущена несколько раз в разных местах, если транзакция откат. Что произойдет, если вы запустите свою транзакцию, она выполняет операцию ввода-вывода и затем откатывается при записи результатов в переменных?

По этой причине вычисления STM должны быть чистыми, только с добавлением STM-примитивов, таких как изменяемые переменные STM и массивы.

+0

Конечно, не имеет смысла выполнять операции ввода-вывода внутри транзакции; вы не можете отменить ввод-вывод. Но можно ли использовать транзакции для достижения взаимного исключения? И разумно ли это делать? – MathematicalOrchid

+0

@MathematicsOrchid Насколько я знаю, взаимное исключение не может быть сделано в STM. Нет никаких гарантий того, что инфраструктура STM будет ждать чего угодно - она ​​также может повторять неудачную транзакцию снова и снова в цикле до тех пор, пока она не удастся. Из [docs] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/GHC-Conc-Sync.html#v:retry): * Реализация может блокировать поток до тех пор, пока один обновленных ТВАР. * Вероятно, наилучшим решением является ответ, заданный _comonad_ - как я понимаю, он выполняет действия «IO» при успешной фиксации. –

+0

@MathematicsOrchid Просто мысль, возможно ли достичь как взаимной эксклюзивности, так и композиционной способности, не рискуя зайти в тупик? –

6

Используйте TVar Bool с именем consistent, чтобы отслеживать, выполняется ли ваше действие ввода-вывода. Перед выполнением действия ввода-вывода вы устанавливаете соответствие с False, и после запуска операции ввода-вывода вы устанавливаете consistent в True. Тогда, любое действие, которое зависит от значений этой STM переменных, которые вы модифицирующие просто ставит этот пункт в начале:

do b <- readTVar consistent 
    check b 
    ... 

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

+0

У этого есть вкус. В настоящее время проблема, с которой я сталкиваюсь, заключается в том, что действие mutex не может запускать другие действия mutex, поскольку мьютекс уже выполнен. Я не уверен, что вышеупомянутый подход решит эту проблему ... – MathematicalOrchid

+0

Можете ли вы уточнить проблему мьютекса? –

+0

Если вы используете 'MVar()' как мьютекс и начинаете каждую функцию с помощью 'takeMVar', то одна функция не может вызвать другую, поскольку мьютекс уже сделан. Функции становятся несовместимыми. – MathematicalOrchid

4

Я думаю, что вы ищете пакет stm-io-hooks.

Независимо от того, что вы на самом деле хотите сделать - можно ли было бы выразить это в терминах семантики прерывания/повтора STM? Другими словами: Можете ли вы выполнить откат и повторить действие IO? Если нет, то я бы назвал ответ Габриэля Гонсалеса.

+0

Ну, все операции ввода-вывода - _read_, поэтому единственное, что они изменяют, это состояние дескриптора. Если бы вы могли гарантировать, что две операции ввода-вывода не будут выполняться одновременно, и каждый всегда будет искать нужное место в первую очередь ... это _might_, возможно, работает ... Но я думаю, что сохранение операций ввода-вывода с транзакциями будет работать лучше , – MathematicalOrchid

+1

@MathematicsOrchid: В этом случае я бы просто использовал разные Ручки. Если это не вариант, вам нужно будет использовать механизм блокировки (MVar или ответ Габриэля) для поиска + чтения. – comonad

+0

@MathematicsOrchid: Я не уверен, для чего вам нужен STM, но, возможно, вы просто экспериментируете с параллелизмом. Вам не нужны мьютексы, как на более низких языках: в Haskell вы применяете механизм блокировки непосредственно к ресурсу, например 'MVar Handle' вместо' (MVar(), Handle) '. STM - это совершенно другой способ решения проблем параллелизма, он использует транзакции, которые могут быть прерваны/восстановлены/повторены как денежная транзакция между банковскими счетами. Я не вижу в этом ничего для чтения неизменяемых файлов. – comonad

Смежные вопросы