Haskell线程通信模式场景

Ani*_*tla 11 multithreading haskell design-patterns communication

你有两个线程,a和b.线程a处于永久循环中,侦听阻塞套接字1.线程b也处于永久循环中,侦听阻塞套接字2.套接字1和套接字2都可以在任意时间返回数据,因此线程a可能永远在睡觉等待数据,而线程b不断从套接字获取数据并继续处理.这就是背景.

现在假设他们需要共享字典.当线程a获取一些数据(如果有的话)时,它会在一些处理之后将一个键值对添加到字典中,然后继续等待更多数据.当线程b从其套接字接收数据时,它首先查询字典,以查看在继续处理之前是否存在与其已接收的数据相关的信息.字典没有删除,只有插入和查询(如果这在最终解决方案中有所不同,我会感兴趣).

在像python或c这样的标准命令式语言中,通过使字典在两个作用域中都可用并且仅在线程获得锁定后查询它,这很容易做到,因此线程B总是看到最多(几乎是)最新的字典.

在Haskell中,我似乎正在努力想出这个模式的良好实现.MVars,一次只能有一个项目因此不能将一个项目放入字典中,因为可能会发生新的更新,并且在线程b从MVar中获取它之前它将无法推送新的字典.另一方面,如果线程b使用MVar发送就绪信号"ok!" 线程a,可能是Thread a在其读取套接字上休眠的情况,因此在读取套接字解除阻塞之前它将无法发回数据!还有频道,但这似乎很混乱,因为我不得不继续发送新词典,而线程B将丢弃除最后一个之外的所有字典.

可行的替代解决方案是简单地沿着通道发送更新,并让线程B为自己构建字典.但是我想知道是否有更好的替代解决方案.

感谢您花时间阅读这个很长的问题!

Dan*_*her 10

您可以通过MVar以下方式使用:

  • 当线程A获取新数据时,它会尝试获取字典takeMVar.当成功时,它会更新字典并将其重新放入MVar
  • 当线程B获取数据时,它会尝试使用takeMVar- 在上面的场景中获取字典,其中A很少获得平均成功相当快的数据.然后它执行查找并将字典放回去.

正如hammar指出的那样,最好不要直接使用takeMVar,putMVar而是将它们包装在modifyMVar_resp中.如果一个线程在使用字典时获得异常,则modifyMVar不要MVar留空.

在线程A中,类似于

modifyMVar_ mvar (\dict -> putMVar mvar (insert newStuff dict))
Run Code Online (Sandbox Code Playgroud)

在线程B中你需要的只是一个简单的readMVar(再次感谢@hammar指出这一点).