Сценарий шаблона связи потока Хаскелла - PullRequest
11 голосов
/ 03 января 2012

У вас есть две темы, а и б. Поток a находится в бесконечном цикле, прослушивая блокирующий сокет 1. Поток b также находится в вечном цикле, прослушивая блокирующий сокет 2. И сокет 1, и сокет 2 могут возвращать данные в произвольные моменты времени, поэтому поток А может спать вечно ожидание данных, тогда как поток b постоянно получает данные из сокета и продолжает их обработку. Это фон.

Теперь предположим, что им нужен общий словарь. Когда Thread a получает некоторые данные (если вообще когда-либо), он добавляет пару значений ключа в словарь после некоторой обработки, а затем продолжает ожидать получения дополнительных данных. Когда поток b получает данные из своего сокета, он сначала запрашивает словарь, чтобы узнать, есть ли информация, связанная с данными, которые он получил, прежде чем приступить к его обработке. В словаре нет удалений, только вставки и запросы (мне было бы интересно, если бы это имело значение в конечном решении).

В стандартном императивном языке, таком как python или c, это довольно легко сделать, сделав словарь доступным в обеих областях и запрашивая его только после того, как поток получил блокировку, поэтому поток B всегда видит больше всего (почти) современный словарь.

В Хаскеле я, кажется, изо всех сил пытаюсь придумать хорошую реализацию этого шаблона. MVars, может иметь только один элемент за раз, поэтому не может быть, чтобы Thread a помещал в словарь, так как может произойти новое обновление, и он не сможет выдвинуть этот новый словарь, пока Thread b не выберет его из MVar. С другой стороны, если поток b использует MVar для отправки сигнала о готовности "ok!" для потока a, может случиться так, что поток a спит на своем сокете чтения, поэтому он не сможет отправить данные обратно, пока его сокет чтения не разблокируется! Есть также каналы, но это кажется грязным, так как мне пришлось бы продолжать посылать новые словари, а тема B отбрасывала бы все, кроме последнего.

Альтернативное решение, которое будет работать, - это просто отправить обновления по каналу, а поток B создаст словарь для себя. Однако мне интересно, есть ли лучшие альтернативные решения.

Спасибо, что нашли время, чтобы прочитать этот очень длинный вопрос!

1 Ответ

10 голосов
/ 03 января 2012

Вы можете использовать MVar следующим образом:

  • Когда поток A получает новые данные, он пытается получить словарь с takeMVar.Когда это удается, он обновляет словарь и помещает его обратно в MVar
  • Когда поток B получает данные, он пытается получить словарь с помощью takeMVar - в приведенном выше сценарии, где A редко получает данные, которыедолжен преуспеть довольно быстро в среднем.Затем он выполняет поиск и возвращает словарь обратно.

Как указывал Хаммар, вероятно, лучше не напрямую использовать takeMVar и putMVar, а вместо этого обернуть их в modifyMVar_ соответственно.modifyMVar чтобы не оставлять MVar пустым, если один поток получает исключение при использовании словаря.

В потоке A, что-то вроде

modifyMVar_ mvar (\dict -> putMVar mvar (insert newStuff dict))

в потоке B, все, что вам нужно, этопростой readMVar (еще раз спасибо @hammar за указание на это).

...