Multithreading readMVar不';不要在putMVar上醒来
在另一个线程调用Multithreading readMVar不';不要在putMVar上醒来,multithreading,haskell,ghc,Multithreading,Haskell,Ghc,在另一个线程调用putMVar之后,我的代码似乎挂在readMVar上。我没想到会发生这种事,但这就是我观察到的。我的主线程创建两个新线程,每个线程都可以访问共享的MVarm 线程1: do putStrLn "tick" x <- readMVar m putStrLn "tock" 主要内容: 这是怎么回事?我希望应该打印“tock”,因为线程2填充了MVar,但我的程序只是挂起。在调试空间泄漏时,我将MVar实现从base切换到严格并发。但是,正如问题所指出的,我的代码
putMVar
之后,我的代码似乎挂在readMVar
上。我没想到会发生这种事,但这就是我观察到的。我的主线程创建两个新线程,每个线程都可以访问共享的MVar
m
线程1:
do
putStrLn "tick"
x <- readMVar m
putStrLn "tock"
主要内容:
这是怎么回事?我希望应该打印“tock”,因为线程2填充了MVar,但我的程序只是挂起。在调试空间泄漏时,我将MVar实现从
base
切换到严格并发。但是,正如问题所指出的,我的代码使用了tryReadMVar
,由于某些原因,严格并发
没有提供它。因此,不久前,我自己实现了tryReadMVar
如下:
tryReadMVar :: (NFData a) => MVar a -> IO (Maybe a)
tryReadMVar m = do
mm <- tryTakeMVar m
case mm of
Nothing -> return ()
Just a -> putMVar m a
return mm
tryReadMVar::(NFData a)=>MVar a->IO(可能是a)
tryReadMVar m=do
毫米返回()
只是一个->putMVar m a
返回mm
没有真正考虑其影响。从那以后,我就完全忘记了做这件事。正如Daniel指出的那样,base
的旧版本曾经做过类似的事情,但新版本有一个原子的tryReadMVar
实现。因此,尽管我使用的是GHC的新版本,但由于使用了严格并发
,这个问题再次被引入
同时,僵局发生在以下情况下(Daniel描述):
- 线程1打印“勾号”
- 线程2使用
putMVar
- 螺纹2打印“放置m0”
- 线程1在
tryReadMVar
- 线程2使用
tryTakeMVar
- thread2打印“take m”
- thread2使用
putMVar
- 螺纹2打印“放置m1”
- 线程1在
tryReadMVar
事实证明,拥有一个原子tryReadMVar
非常有用 什么版本的GHC?在旧版本中,readMVar
是一个takeMVar
,后跟一个putMVar
(非原子执行)。如果tryTakeMVar
和第二个putMVar
发生在两者之间,这将解释您看到的行为。我相信GHC 8.6.3,尽管使用堆栈时有点难说。但是,如果你解释得很清楚,我将尝试深入了解使用的是哪个版本。确认它是GHC 8.6.3。问题是:我使用的是严格并发,它不提供tryReadMVar
。因此,我自己使用tryTakeMVar
和putMVar
(非原子性)实现了它。因此,丹尼尔说的是正确的。你应该写下来作为答案。跟踪它做得很好。我创建了一个问题,严格并发
请求添加tryReadMVar
,这样其他人就不会犯同样的错误。
do
m <- newEmptyMVar
<start thread 1>
<start thread 2>
tick
put m0
take m
put m1
<hang>
tryReadMVar :: (NFData a) => MVar a -> IO (Maybe a)
tryReadMVar m = do
mm <- tryTakeMVar m
case mm of
Nothing -> return ()
Just a -> putMVar m a
return mm