Scala同步消费者生产者

时间:2014-03-07 19:19:01

标签: multithreading scala producer-consumer

我想实现生产者 - 消费者问题(一次只传输一个信息),但我希望制作人在离开前等待某人接收他的信息。

这是一个不阻止生产者的例子,但不是这样。

class Channel[T]
{
private var _msg : Option[T] = None

def put(msg : T) : Unit =
{
    this.synchronized
    {
        waitFor(_msg == None)

        _msg = Some(msg)

        notifyAll
    }
}

def get() : T =
{
    this.synchronized
    {
        waitFor(_msg != None)

        val ret = _msg.get

        _msg = None

        notifyAll

        return ret
    }
}

private def waitFor(b : => Boolean) =
    while(!b) wait
}

如何更改它以便生产者被阻止(作为消费者)?

我试图在结束时添加另一个waitFor,但有时我的制作人不会被释放。

例如,如果我有put ; get || get ; put,大部分时间都有效,但有时,第一个put没有终止,左线程甚至从不运行get方法(我会在put调用终止后打印一些内容,在这种情况下,它永远不会打印出来。

3 个答案:

答案 0 :(得分:2)

这就是为什么你应该在这种情况下使用标准类SynchronousQueue

如果您真的想要处理有问题的代码,请首先向我们提供一个失败的测试用例或堆栈跟踪时的堆栈跟踪。

答案 1 :(得分:0)

您可以通过BlockingQueue后代执行此操作,其生成器put()方法创建一个信号量/事件对象,该对象使用传递的消息排队,然后生产者线程等待它。

使用者get()方法从队列中提取消息并发出信号,从而允许其原始生成器运行。

这允许同步队列'实际的排队功能,应该是你想要的吗?

答案 2 :(得分:0)

我想出了一些似乎有用的东西。

class Channel[T]
{
    class Transfer[A]
    {
        protected var _msg : Option[A] = None

        def msg_=(a : A) = _msg = Some(a)
        def msg : A =
        {
            // Reading the message destroys it
            val ret = _msg.get
            _msg = None
            return ret
        }

        def isEmpty = _msg == None
        def notEmpty = !isEmpty
    }

    object Transfer {
        def apply[A](msg : A) : Transfer[A] =
        {
            var t = new Transfer[A]()
            t.msg = msg
            return t
        }
    }

    // Hacky but Transfer has to be invariant
    object Idle extends Transfer[T]

    protected var offer : Transfer[T] = Idle
    protected var request : Transfer[T] = Idle

    def put(msg : T) : Unit =
    {
        this.synchronized
        {
            // push an offer as soon as possible
            waitFor(offer == Idle)
            offer = Transfer(msg)

            // request the transfer
            requestTransfer

            // wait for the transfer to go (ie the msg to be absorbed)
            waitFor(offer isEmpty)

            // delete the completed offer
            offer = Idle
            notifyAll
        }
    }

    def get() : T =
    {
        this.synchronized
        {
            // push a request as soon as possible
            waitFor(request == Idle)
            request = new Transfer()

            // request the transfer
            requestTransfer

            // wait for the transfer to go (ie the msg to be delivered)
            waitFor(request notEmpty)
            val ret = request.msg

            // delete the completed request
            request = Idle
            notifyAll
            return ret
        }
    }

    protected def requestTransfer()
    {
        this.synchronized
        {
            if(offer != Idle && request != Idle)
            {
                request.msg = offer.msg
                notifyAll
            }
        }
    }

    protected def waitFor(b : => Boolean) =
     while(!b) wait
}

它具有尊重生产者和消费者之间对称性的优势,但它比我之前的要长一些。

感谢您的帮助。

编辑:它更好但仍然不安全......