Haskell中的读写器锁

多纳泰洛

我正在实现一个在内存中保存一些数据的Web应用程序。一些请求读取此数据以进行处理,而某些请求更新此数据。

在这种情况下,多个读取器可以同时对数据进行操作,但是写入器需要对内存中的数据进行独占访问。我想实现读写器锁来解决此问题。我还希望公平性属性,即按FIFO顺序处理锁上的服务员,以避免读写不足。

Haskell标准库似乎没有提供这种功能。我发现concurrency-extra提供了此功能,但该库似乎未维护(在LTS 3.22之后已从堆栈中删除)-其公平性对我而言并不明确。

我感到有点奇怪,在标准的haskell库和堆栈中没有读写器锁定库-读写器模式在许多软件中不是常见的吗?还是在Haskell中有一种完全不同的(也许是无锁的)首选方法?

编辑:更准确地说,在公平属性上,当写作者被阻止等待获取锁时,仅在写者获得并释放写锁之后才应允许后续的读锁定请求-与MVars公平属性类似-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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Android中的读写器任务队列

来自分类Dev

pthread读写器锁和基于fcntl()的文件锁之间有什么区别?

来自分类Dev

异步读写器储物柜

来自分类Dev

vtkXMLPolyData读写器不可逆

来自分类Dev

关闭读写器的异常处理

来自分类Dev

异步读写器储物柜

来自分类Dev

如何检测读写器问题中的饥饿

来自分类Dev

Java:如何解决读写器问题?

来自分类Dev

C ++中的读写锁实现

来自分类Dev

线程安全销毁C中的读写锁

来自分类Dev

线程安全销毁C中的读写锁

来自分类Dev

使用ACR122U作为读写器在Windows Form Application C#中将Ndef写入NFC标签

来自分类Dev

使用ACR122U作为读写器在Windows Form Application C#中将Ndef写入NFC标签

来自分类Dev

Java的侦听器是否具有读写锁?

来自分类Dev

并发文件在Haskell中读写?

来自分类Dev

在进程间共享读写锁

来自分类Dev

无锁读写无序安全

来自分类Dev

在内核中使用读写锁死锁

来自分类Dev

仅具有一个基础锁的读写锁?

来自分类Dev

如何从CSV文件(在C中)读写寄存器?

来自分类Dev

用MSSQL服务器中的行锁更新

来自分类Dev

在Google表格脚本编辑器中闩锁

来自分类Dev

VS2012中的并发分析-读者编写器锁

来自分类Dev

访问外部USB中的位锁驱动器

来自分类Dev

在锁屏中配置多显示器

来自分类Dev

在嵌套的 If-Else 语句 (VHDL) 中推断锁存器

来自分类Dev

维基百科的读写锁实现是否正确?

来自分类Dev

什么是Haskell中的组合器

来自分类Dev

Haskell中的S组合器