繁体   English   中英

TMVar,但是没有缓冲区?

[英]TMVar, but without the buffer?

我正在尝试在Haskell轻量级线程之间进行通信。 线程希望互相发送消息以进行通信和同步。

我最初是使用TMVar来实现此目的的,但我刚刚意识到语义是错误的: TMVar会在内部在其中存储一条消息,因此不会将消息存储到空的TMVar 仅当您将消息发布到完整的 TMVar

谁能建议一个类似的STM IPC结构:

  • 将导致所有写入阻塞,直到消息被消耗为止;
  • 会导致所有读取阻塞,直到提供消息?

即零长度的管道将是理想的; 但我不认为BoundedChan的容量为0会感到高兴。(而且,这不是STM 。)

如果我正确地理解了您的问题,那么我认为您不会,因为事务性保证意味着事务A在提交事务B之前无法从事务B的写入中读取,此时事务B无法再阻塞。

如果使用STM, TMVar是最接近的。 使用IO,您可能能够构建仅在有读者可用时才能完成写入的结构(该结构可能已经存在,但我不知道)。

我建议重新制定两个要求:

  • 将导致所有写入阻塞,直到消息被消耗为止;
  • 将阻止所有读取,直到提供消息为止。

问题在于条款受阻消费/提供 在STM中,没有block的概念,而只是retry ,它具有不同的语义:它重新启动当前事务-它不等到发生某种事情(这可能导致死锁)。 因此我们不能说“直到...才阻止”,我们只能说诸如“只有当...时交易才成功”。

同样,“直到消费/提供一条消息”是什么意思? 由于事务是原子的,因此只能是“直到消耗/提供消息的事务成功为止”。

因此,让我们尝试重新制定:

  • 将导致所有写入重试,直到消耗该消息的事务成功为止;
  • 将导致所有读取重试,直到提供消息的事务成功为止。

但是现在,第一点没有意义:如果写入重试,没有消息要使用,事务没有暂停,它被丢弃并重新开始-可能会产生不同的消息!

换句话说:任何数据只有在成功(完成)后才能离开STM事务。 这是设计使然-从外部世界/其他事务的角度来看,事务始终是原子的-您永远无法观察到仅一部分事务的结果。 您永远不会观察到两个事务交互。

因此,长度为0的队列是一个不好的类比-尽管它永远不允许传递任何数据。 在任何事务结束时,都必须为空,因此不会有任何数据通过。

不过,我相信可以根据您的目标重新制定需求,然后找到解决方案。

您说您会对一侧或另一侧使用IO而不是STM感到满意。 因此,编写起来并不太困难。 让我们从IO中接收的版本开始。 为了做到这一点,接收机将必须发起握手。

type SynchronousVar a = TChan (TMVar a)

send :: SynchronousVar a -> a -> STM a
receive :: SynchronousVar a -> IO a

send svar a = do
    tmvar <- readTChan svar
    putTMVar tmvar a

receive svar = do
    tmvar <- newEmptyTMVarIO
    atomically $ writeTChan svar tmvar
    atomically $ takeTMVar tmvar

可以编写类似的协议,该协议已开始发送握手。

type SynchronousVar a = TChan (a, TMVar ())

send :: SynchronousVar a -> a -> IO a
receive :: SynchronousVar a -> STM a

send svar a = do
    tmvar <- newEmptyTMVarIO
    atomically $ writeTChan svar (a, tmvar)
    atomically $ takeTMVar tmvar

receive svar = do
    (a, tmvar) <- readTChan svar
    putTMvar tmvar ()
    return a

可能是,如果您确实需要同步通信,那是因为您想要双向通信(即, IO运行的操作想了解与其同步的线程有关的信息)。 不难扩展上述协议以传递更多有关同步的信息(通过在前一种情况下将其添加到一个元组或在后一种情况下将其添加到TMVar )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM