数据竞争?或者其他什么问题?

Bit*_*ler 4 ponylang

今天就找到了编程语言"pony"......并开始玩它.

我的代码应该做一些简单的生产者消费者的事情.正如语言文档所声称的,该语言确保没有数据竞争.

这里,main向生产者发送10条消息,生产者又向消费者发送10条消息.消费者递增计数器状态变量.然后,main向消费者发送消息,消费者又向main发送消息以显示当前值.如果所有消息都按顺序排列,则预期值将为9(或10).打印结果虽然是0.

因为这是我用语言玩的第一个小时,当然我可能搞砸了别的东西.

谁可以解释我的错误?

use "collections"

actor Consumer 
    var _received : I32
    new create() =>
        _received = 0
    be tick() =>
        _received = _received + 1
    be query(main : Main) =>
        main.status(_received)

actor Producer
    var _consumer : Consumer
    new create(consumer' : Consumer) =>
        _consumer = consumer'

    be produceOne () =>
        _consumer.tick()

actor Main
    var _env : Env 
    new create(env: Env) =>
        _env = env
        let c : Consumer = Consumer.create()
        let p = Producer.create(c)
        for i in Range[I32](0,10) do
            p.produceOne()
        end
        c.query(this)

    be status( count : I32) =>
        // let fortyTwo : I32 = 42
        // _env.out.print( "fortytwo? " + (fortyTwo.string()))
        _env.out.print( "produced: " + (count.string()) )
Run Code Online (Sandbox Code Playgroud)

在Windows 10,64 bit,btw上运行.我找到了最新最好的zip文件安装.

0.10.0-1c33065 [发布]编译:llvm 3.9.0 - ?

小智 5

Pony阻止的数据竞争是在内存级别发生的,当有人从内存位置读取而其他人正在写入时.通过禁用类型系统的共享可变状态来防止这种情况.

但是,如果结果取决于Pony无法保证的消息排序,则您的程序仍然可以进行"逻辑"数据竞争.Pony保证消息的因果排序.这意味着,如果消息具有相同的目的地,则发送或接收的消息是将要发送或接收的任何未来消息的原因,当然,必须在其影响之前发生原因.

actor A
  be ma(b: B, c: C) =>
    b.mb()
    c.mc(b)

actor B
  be mb() =>
    None

actor C
  be mc(b: B) =>
    b.mb()
Run Code Online (Sandbox Code Playgroud)

在此示例中,B将始终从消息A之前接收消息,C因为在A发送消息B之前发送消息C(请注意,仍然可以按任何顺序接收这两个消息,因为它们没有相同的目的地).这意味着,发送给消息B通过C后发送到消息被发送B通过A并且由于都具有相同的目的地,有因果关系.

让我们看看你的程序中的因果排序.我们拥有->"是事业的原因"

  • Main.create -> Main.status(通过Consumer.query)
  • Consumer.create -> Consumer.query
  • Consumer.create -> Consumer.tick(通过Producer.produceOne)
  • Producer.create -> Producer.produceOne

如你所见,Consumer.query和之间没有因果关系Consumer.tick.在实际实现的意义上,这意味着Main可以发送produceOne消息,然后query在任何Producer开始执行它收到的消息之前发送消息,并且有机会发送tick消息.如果您使用一个调度程序线程(--ponythreads=1作为命令行参数)运行程序,它将始终打印,produced: 0因为Main将独占调度程序直到结束create.使用多个调度程序线程时,可能会发生0到10之间的任何事情,因为所有调度程序可能忙于执行其他actor,或者可以Producer立即开始执行s.

总之,您tickquery行为可以按任何特定顺序执行.要解决这个问题,你必须通过添加往返消息或在同一个actor中进行累积和打印来引入消息之间的因果关系.