我正在实现一个在内存中保存一些数据的Web应用程序。一些请求读取此数据以进行处理,而某些请求更新此数据。
在这种情况下,多个读取器可以同时对数据进行操作,但是写入器需要对内存中的数据进行独占访问。我想实现读写器锁来解决此问题。我还希望公平性属性,即按FIFO顺序处理锁上的服务员,以避免读写不足。
Haskell标准库似乎没有提供这种功能。我发现concurrency-extra
提供了此功能,但该库似乎未维护(在LTS 3.22之后已从堆栈中删除)-其公平性对我而言并不明确。
我感到有点奇怪,在标准的haskell库和堆栈中没有读写器锁定库-读写器模式在许多软件中不是常见的吗?还是在Haskell中有一种完全不同的(也许是无锁的)首选方法?
编辑:更准确地说,在公平属性上,当写作者被阻止等待获取锁时,仅在写者获得并释放写锁之后才应允许后续的读锁定请求-与MVar
s公平属性类似-MVar
具有FIFO财产
最好的解决方案取决于读者/作家的关系,但是我认为您只能使用解决问题MVar
。
让
import System.Clock
import Text.Printf
import Control.Monad
import Control.Concurrent
import Control.Concurrent.MVar
t__ :: Int -> String -> IO ()
t__ id msg = do
TimeSpec s n <- getTime Realtime
putStrLn $ printf "%3d.%-3d - %d %s" (s `mod` 1000) n id msg
reader :: MVar [Int] -> Int -> IO ()
reader mv id = do
t__ id $ "reader waiting"
xs <- readMVar mv
t__ id $ "reader working begin"
threadDelay (1 * 10^6)
t__ id $ "reader working ends, " ++ show (length xs) ++ " items"
writer :: MVar [Int] -> Int -> IO ()
writer mv id = do
t__ id $ "WRITER waiting"
xs <- takeMVar mv
t__ id $ "WRITER working begin"
threadDelay (3 * 10^6)
t__ id $ "WRITER working ends, " ++ show (1 + length xs) ++ " items"
putMVar mv (id: xs)
main = do
mv <- newMVar []
forM_ (take 10 $ zipWith (\f id -> forkIO (f mv id)) (cycle [reader, reader, reader, writer]) [1..]) $ \p -> do
threadDelay (10^5)
p
getLine
带输出
c:\tmp>mvar.exe +RTS -N20
486.306991300 - 1 reader waiting
486.306991300 - 1 reader working begin
486.416036100 - 2 reader waiting
486.416036100 - 2 reader working begin
486.525191000 - 3 reader waiting
486.525191000 - 3 reader working begin
486.634286500 - 4 WRITER waiting
486.634286500 - 4 WRITER working begin
486.743378400 - 5 reader waiting
486.852406800 - 6 reader waiting
486.961564300 - 7 reader waiting
487.070645900 - 8 WRITER waiting
487.179673900 - 9 reader waiting
487.288845100 - 10 reader waiting
487.320003300 - 1 reader working ends, 0 items
487.429028600 - 2 reader working ends, 0 items
487.538202000 - 3 reader working ends, 0 items
489.642147400 - 10 reader working begin
489.642147400 - 4 WRITER working ends, 1 items
489.642147400 - 5 reader working begin
489.642147400 - 6 reader working begin
489.642147400 - 7 reader working begin
489.642147400 - 8 WRITER working begin
489.642147400 - 9 reader working begin
490.655157400 - 10 reader working ends, 1 items
490.670730800 - 6 reader working ends, 1 items
490.670730800 - 7 reader working ends, 1 items
490.670730800 - 9 reader working ends, 1 items
490.686247400 - 5 reader working ends, 1 items
492.681178800 - 8 WRITER working ends, 2 items
当下4 WRITER working begin
一个请求等待读取器1、2和3终止时,读取器1、2和3会同时运行。
(在此示例中,stdout输出和进入FIFO的流程订单不准确,但读取或结算的项目数显示了实际订单)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句