Способ формирования "выбора" на MVars без опроса

У меня есть два MVars (ну, MVar и Чан). Мне нужно вытащить вещи из Чана и обработать их, пока другой MVar больше не будет пустым. Моим идеальным решением было бы что-то вроде UNIX select функция, в которой я передаю список (предположительно пустых) MVars и блоков потоков, пока один из них не заполнится, затем он возвращает полный MVar. Попробуйте, как я мог бы, я не могу думать ни о каком способе сделать это кроме повторного опроса каждого MVar с isEmptyMVar, пока я не получу false. Это кажется неэффективным.

Другая идея заключалась в том, чтобы использовать throwTo, но это прерывает то, что когда-либо происходит в потоке, и мне нужно завершить обработку работы с Чаном атомарным способом.

Последняя мысль, которую я набираю, - создать новый forkIO для каждого MVar, который пытается прочитать свой MVar, а затем заполнить вновь созданный MVar своим собственным экземпляром. Исходный поток может затем заблокировать этот MVar. Являются ли потоки на Haskell достаточно дешевыми для запуска такого количества?

2 ответа

Решение

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

do var <- atomically (takeTMVar a `orElse` takeTMVar b)
   ... do stuff with var

Из-за поведения retry а также orElseэтот код пытается получить aтогда, если это не удастся, получите b, Если оба сбоя, он блокируется, пока один из них не будет обновлен и пытается снова.

Вы даже можете использовать это, чтобы сделать свою собственную элементарную версию select:

select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar

Как насчет использования версий STM, TChan а также TVarс retry а также orElse поведение?

Реализация select - одна из приятных возможностей STM. Из "Композиционные транзакции памяти":

Помимо этого, мы также предоставляем orElse, который позволяет им составляться как альтернативы, так что вторая запускается, если первая попытка повторяется (раздел 3.4). Эта способность позволяет потокам одновременно ожидать много вещей, как, например, системный вызов select Unix - за исключением того, что orElse хорошо скомпонован, а select - нет.


Другие вопросы по тегам