Haskell: поток заблокирован на неопределенный срок в транзакции STM

#multithreading #haskell #stm

#многопоточность #haskell #stm

Вопрос:

Есть ли какой-либо способ увеличить интервал времени, на основе которого RTS решает, что поток заблокирован на неопределенный срок в транзакции STM? Вот мой код:

 import Control.Concurrent (ThreadId)
import Control.Concurrent.MVar (MVar,newMVar,withMVar)
import Control.Concurrent.STM
import qualified Control.Concurrent.ThreadManager as TM

data ThreadManager = ThreadManager { tmCounter::TVar Int, tmTM::MVar TM.ThreadManager }

data Settings = Settings {
    maxThreadsCount::Int }

createThreadManager :: Settings -> IO ThreadManager
createThreadManager s = do
    counter <- atomically $ newTVar (maxThreadsCount s)
    tm <- TM.make >>= newMVar
    return $ ThreadManager counter tm

forkManaged :: ThreadManager -> IO () -> IO ThreadId
forkManaged tm fn = do
    atomically $ do
        counter <- readTVar $ tmCounter tm
        check $ counter > 0
        writeTVar (tmCounter tm) (counter - 1)
    withMVar (tmTM tm) $ thrdmgr -> TM.fork thrdmgr $ do
        fn
        atomically $ do
            counter <- readTVar $ tmCounter tm
            writeTVar (tmCounter tm) (counter   1)
  

forkManaged гарантирует, что количество одновременно запущенных управляемых потоков не превышает maxThreadsCount . Он отлично работает до большой нагрузки. При большой нагрузке RTS выдает исключение. Я думаю, что при большой нагрузке, при жесткой параллельной конкуренции за ресурсы, у некоторых потоков просто нет времени, чтобы получить доступ к контексту STM. Поэтому я думаю, что увеличение временного интервала, когда RTS решает выдать это исключение, может решить проблему.

Комментарии:

1. Вы уверены, что решение принято с тайм-аутами? Я думал, что он использует свои журналы, чтобы решить, когда два retry s ожидают друг друга.

2. @Daniel: Даниэль, я обновил вопрос, предоставив свой код с использованием STM. Вот почему я думаю, что проблема с таймаутом.

3. Возможно ли, что fn это создает исключение и предотвращает увеличение счетчика?

4. @Daniel: Я прав, если возникло исключение, которое не было обнаружено в моем коде, тогда я должен увидеть его в консоли? На самом деле эти fn выполняют некоторые действия в IO, но эти действия передаются в Control. Exception.catch , и я не вижу никаких жалоб в консоли.

Ответ №1:

Дэниел Вагнер прав. Решение не принимается с тайм-аутами. Соответствующий код в rts находится в Schedule.c

Смотрите resurrectThreads функцию, в которой генерируется исключение. В комментарии описывается, что это выбрасывается только в потоки, признанные мусорными после GC. эзянг описал, как это работает для mvar’ов: http://blog.ezyang.com/2011/07/blockedindefinitelyonmvar /

[плохое предположение относительно check удалено, когда я проверил его источник и понял, что это была просто простая защита / повторная попытка, а не то, что было описано в более ранней статье — упс! Теперь я подозреваю, что Дэниел Вагнер и здесь прав, и проблема в том, что счетчик не увеличивается.]

Комментарии:

1. Sclv, Даниэль, спасибо за ответ, особенно за полезные ссылки на реализацию rts ghc! Я проверю свой код еще раз.