I'm new at Haskell and stm and I wanted to make a simple rwlock. First I created the 4 main functions (wlock, wunlock, rlock, runlock) that requires 2 TVar Integers: the amount of reading threads and writing threads.
At this point I can't use it as intended. I try to compile like this
v1 <- atomically(newTVar 0);
v2 <- atomically(newTVar 0);
wlock v1 v2 -- wlock :: TVar Integer -> TVar Integer -> IO ()
which of course is ugly, but it works (not sure why because atomically returns IO (TVar a)
instead of TVar a
)
What I want:
I'm trying to make it better by hiding the values. I read somewhere that monads might be the way to go, but I haven't study them yet. Instead, I try to make a new type Rwlock as
data Rwlock = Rwlock { readCant :: TVar Integer
,writeCant :: TVar Integer
}
and a constructor, so I can do something like this:
import Rwlock
do{
a = rwconst;
forkIO(reader a);
forkIO(writer a);
}
where reader will call rlock a
, and writer wlock a
.
The problem:
I can't make the constructor. This is what I try (ignore maxLectores
)
(A):
rwconst :: Integer -> Rwlock
rwconst n = Rwlock {readCant = TVar 0, writeCant = TVar 0, maxLectores = n}
{-rwconst n = Rwlock {readCant = atomically(newTVar 0), writeCant = atomically(newTVar 0), maxLectores = n}-}
But TVar constructor is not exported, and nothing returns a TVar. I don't know why the first block of code works when I do wlock v1 v2
, but this way it doesn't.
And (B):
rwconst :: Integer -> Rwlock
rwconst n = do
a <- (atomically(newTVar 0));
Rwlock {readCant = a, writeCant = a, maxLectores = n}
Here Rwlock doesn't have a problem, but the do statement returns IO(), instead of Rwlock as I want, and I can't found how to do it.
Anyone can tell me the way to do it? Thanks in advance.
Allocating locks requires doing IO, and you can't get around that. So admit it in the type for your action:
rwconst :: Integer -> IO Rwlock
rwcost n = do
rcount <- newTVarIO 0
wcount <- newTVarIO 0
return Rwlock { readCant = rcount, writeCant = wcount, maxLectores = n }
Then, in main
, you can write something like this:
main = do
a <- rwconst 10
forkIO (reader a)
forkIO (writer a)
-- and you should do something to wait for reader and writer to finish