为什么我会通过渠道收到其他元素?

时间:2020-10-21 10:01:07

标签: go channel goroutine

我遇到了一个特殊的问题,不幸的是,我无法在一个最小的工作示例中重现该问题。我会尽力解释,希望您至少能给我一些提示。

我有两个协议: A B 。对于每种协议,只有一个中央方 p1 ,而三个外部方则称为那些 pn 。每一方都是作为单独的goroutine实现的。

协议 A 如下:

  1. 各方分别进行计算,并将其类型*big.Int的结果发送到 p1
  2. p1 接收所有结果并将它们放在一个切片中,然后发送回给每个参与者 pn
  3. 所有参与方都会收到切片,并根据切片执行新的计算,并将其类型*DecryptionShare的结果发送到 p1
  4. p1 接收所有数据并计算结果。
  5. 所有参与方均输出结果*big.Int

为此,我有三个渠道,一个用于发送数据 p1 -> pn ,一个用于 pn -> p1 和一个将最终结果输出回主线程(所有 pn 都从相同的通道读取和写入)。尽管 pn 的结果1.和3.具有不同的类型,所以通道类型为interface{}

协议 B 首先启动协议 A ,然后执行不相关的进一步计算。

这是我的问题:

协议 A 本身没有出现任何问题。 但是,当我打电话给 B 的运行次数约为10%时,即使 B 传递了唯一的区别,它也会惊恐于 A 。将参数输入 A

显示的错误是

panic: interface conversion: interface {} is *big.Int, not *DecryptionShare

暗示 p1 在第4步时收到*big.Int,尽管它在第2步中已经收到了各方*big.Int

我尝试使用time.Sleepselect停留在步骤2更长的时间,但在该步骤中我再也没有得到额外的*big.Int,它只是偶尔出现在步骤4中。 / p>

如果我不是使用chan interface{}而不是使用两个单独的通道chan *big.Intchan *DecryptionShare协议,则 B 正确终止,这也意味着从通道(ei没有线程被阻塞)。我希望避免这种情况,因为我已经在使用许多频道。

有人对为什么发生这种恐慌有任何想法吗?

编辑: 这是一个最小的工作示例,但是不会产生错误。希望它能获得一些见识。 *DecryptionShare替换为int

package tpsi

import (
    "math/big"
    "fmt"
    "crypto/rand"
    "testing"
)

type DecryptionShare struct {
    index int
    p *big.Int
}

func TestErs(t *testing.T) {
    message_channel1 := make(chan interface{})
    message_channel2 := make(chan []*big.Int)
    return_channel := make(chan *big.Int)
    n := 4
    go CentralParty(n, message_channel2, message_channel1, return_channel)
    for i := 1; i < n; i += 1 {
        go OtherParty(message_channel1, message_channel2, return_channel)
    }

    for i := 0; i < n; i += 1 {
        fmt.Println(<-return_channel)
    }
    t.Error("for display")
}

func CentralParty(n int, sender_channel chan<- []*big.Int, reciever_channel <-chan interface{}, return_channel chan<- *big.Int) {
    p, err := rand.Prime(rand.Reader, 256)
    if err != nil {panic(err)}

    all_p := make([]*big.Int, n)
    all_p[0] = p

    for i := 1; i < n; i += 1 {
        all_p[i] = (<-reciever_channel).(*big.Int)
    }

    for i := 1; i < n; i += 1 {
        sender_channel <- all_p
    }

    shares := make([]*DecryptionShare, 4)
    for i := 1; i < n; i += 1 {
        shares[i] = (<-reciever_channel).(*DecryptionShare)
    }

    return_channel <- shares[1].p

}

func OtherParty(sender_channel chan<- interface{}, reciever_channel <-chan []*big.Int, return_channel chan<- *big.Int) {
    p, err := rand.Prime(rand.Reader, 256)
    if err != nil {panic(err)}
    
    sender_channel <- p

    all_p := <-reciever_channel

    var ds DecryptionShare
    ds.p = p
    ds.index = all_p[0].BitLen()
    sender_channel <- &ds

    return_channel <- p

}

1 个答案:

答案 0 :(得分:0)

在几位评论员的共同压力下,我强迫自己获得MWE。而且正如@oakad所建议的那样,我在这样做时发现了该错误。

错误(毫无意外)来自协议 B ,该协议重用了chan interface{},并再次发送了第一个数据类型*big.Int,从而引入了竞争条件。

我完全忽略了考虑各种协议的比赛条件。

谢谢您的评论!